Say I have a shared_ptr
with a custom allocator and a custom deleter.
I can't find anything in the standard that talks about where the deleter should be stored: it doesn't say that the custom allocator will be used for the deleter's memory, and it doesn't say that it won't be.
Is this unspecified or am I just missing something?
util.smartptr.shared.const/9 in C++ 11:
Effects: Constructs a shared_ptr object that owns the object p and the deleter d. The second and fourth constructors shall use a copy of a to allocate memory for internal use.
The second and fourth constructors have these prototypes:
template<class Y, class D, class A> shared_ptr(Y* p, D d, A a); template<class D, class A> shared_ptr(nullptr_t p, D d, A a);
In the latest draft, util.smartptr.shared.const/10 is equivalent for our purpose:
Effects: Constructs a shared_ptr object that owns the object p and the deleter d. When T is not an array type, the first and second constructors enable shared_from_this with p. The second and fourth constructors shall use a copy of a to allocate memory for internal use. If an exception is thrown, d(p) is called.
So the allocator is used if there is a need to allocate it in allocated memory. Based on the current standard and at relevant defect reports, allocation is not mandatory but assumed by the committee.
Although the interface of shared_ptr
allows an implementation where there is never a control block and all shared_ptr
and weak_ptr
are put in a linked list, there is no such implementation in practice. Additionally, the wording has been modified assuming, for instance, that the use_count
is shared.
The deleter is required to only move constructible. Thus, it is not possible to have several copies in the shared_ptr
.
One can imagine an implementation which puts the deleter in a specially designed shared_ptr
and moves it when it the special shared_ptr
is deleted. While the implementation seems conformant, it is also strange, especially since a control block may be needed for the use count (it is perhaps possible but even weirder to do the same thing with the use count).
Relevant DRs I found: 545, 575, 2434 (which acknowledge that all implementations are using a control block and seem to imply that multi-threading constraints somewhat mandate it), 2802 (which requires that the deleter only move constructible and thus prevents implementation where the deleter is copied between several shared_ptr
's).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With