Boost logo

Boost :

Subject: [boost] [shared_ptr] Implicit 2 phase construction with enable_shared_from_this
From: Sebastian Karlsson (sairony_at_[hidden])
Date: 2011-09-01 09:16:40


There's been some discussion about solving the problem with
shared_from_this() not being available in the constructor. This is
fairly natural as shared_ptr ownership doesn't happen until after the
constructor leaves, and we're not even guaranteed that the object
enters shared_ptr ownership at all. What I'm suggesting is the
addition of a private void
enable_shared_from_this<T>::accepted_shared_ptr() {}. Then inside
enable_shared_from_this<T>::_internal_accept_owner we add:

const_cast< T* >( static_cast< const T* >( this ) )->accepted_shared_ptr();

Just beneath: weak_this_ = shared_ptr<T>( *ppx, py );

This allows clients of enable_shared_from_this to add their own
accepted_shared_ptr() which will correctly be called while I believe
not breaking any old code. I just added the const_cast because I'm not
familiar with the rationale behind _internal_accept_owner being const.
This change nets us:

1 ) Generic code dealing with construction of shared_ptrs ( in any of
its forms ) does not need to bother themselves with 2 phase
construction.
2 ) The distinction between construction & transfer of ownership to
shared_ptr makes it easier to cope with both the case where T is not
managed by a shared_ptr and the case where it is.

One gotcha I've found is that for example:

struct foo : enable_shared_from_this< foo >
{
   foo() { boost::shared_ptr< foo > tmp( this, null_deleter() ); } //
We might be allocated on the stack, so use a null_deleter for now
   void accepted_shared_ptr() { /* here we can patch it up with
shared_from_this(), which will use our assigned deletion strategy */ }
}

Does not behave as one would want to. Basically in this case I'd want
to use a shared_ptr<> which makes no assumptions about whether we're
managed by a shared_ptr or not, we want a shared_ptr which acts as a
plain pointer. The problem however is that the shared_ptr which we
construct with the null_deleter will grab the enable_shared_from_this
before even construction is complete. This can be solved by the
following, as seen in boost::make_shared:

...
boost::shared_ptr< foo > empty_with_deleter( static_cast< foo* >( 0 ),
null_deleter() );
boost::shared_ptr< foo > tmp( empty_with_deleter, this ); // This one
is safe to use
...

Which doesn't enter boost::detail::sp_enable_shared_from_this.

Would love some input from someone a bit more knowledgeable about shared_ptr.

Kind regards,
Sebastian Karlsson


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk