Jan Hudec
Jan Hudec

Reputation: 76376

Why does enable_shared_from_this embed a weak pointer instead of embedding the reference counter directly?

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

Answers (3)

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

James Kanze
James Kanze

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

Luc Danton
Luc Danton

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

Related Questions