[shared_ptr] Implicit 2 phase construction with enable_shared_from_this

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
participants (1)
-
Sebastian Karlsson