Reputation: 76376
The enable_shared_from_this
helper contains a weak pointer that is set when creating shared pointer to the object. That means there is the reference-count (allocated separately or together with the object using make_shared
) and an extra weak_ptr
in the object.
Now why doesn't it simply contain the reference count instead? When setting shared_ptr
from dumb pointer, the type has to be fully defined, so the shared_ptr
constructor or assignment operator can detect the type is derived from enable_shared_from_this
and use the correct counter and the format can remain the same, so copying does not care. In fact, the shared_ptr
already has to detect it to set the embedded weak_ptr
.
Upvotes: 10
Views: 1387
Reputation: 208456
The first thing that comes to mind is whether that approach would be feasible at all, and the answer is that it would not:
struct X : enable_shared_from_this {};
std::shared_ptr<X> p( new X );
std::weak_ptr<X> w( p );
p.reset(); // this deletes the object
if ( w.use_count() ) { // this needs access to the count object
// but it is gone! Undefined Behavior
If the count is stored in the object, then no weak_ptr
can outlive the object, which is a breach in the contract. The whole idea of weak_ptr
is that they can outlive the object (if the last shared_ptr
goes out of scope, the object is deleted even if there are weak_ptr
)
Upvotes: 7
Reputation: 154047
To get any advantage from embedding the count in the object, you'ld need
to do away with the second pointer in the shared_ptr
, which would
change its layout, and also create problems for creating the destructor
object. If you change the layout, then this change must be visible
everywhere the shared_ptr
is used. Which means you couldn't have an
instance of the shared_ptr
pointing to an incomplete type.
Upvotes: 1
Reputation: 35469
Separation of concerns: make_shared
to embed the count, enable_shared_from_this
for shared_from_this
.
There's no reason the two should be intermingled: the library can't assume what the client code has for requirements. By separating the two, client code can pick and choose whatever fits best.
In addition Boost (where shared_ptr
comes from) also proposes intrusive_ptr
.
(Consider that your suggestion doesn't seem to allow for custom deleters. You could fix that by changing enable_shared_from_this
to template<typename T, typename Deleter = default_deleter<T>> class enable_shared_from_this;
but by this point it's coming close to reinventing intrusive_ptr
.)
Upvotes: 1