Index: boost/enable_shared_from_this.hpp =================================================================== --- boost/enable_shared_from_this.hpp (revision 43733) +++ boost/enable_shared_from_this.hpp (working copy) @@ -23,9 +23,27 @@ template class enable_shared_from_this { +// dynamic cast to template type doesn't work in constructor, so we have +// to use lazy initialization + void init_internal_shared_once() const + { + if(_owned == false && _internal_shared_this == 0) + { + _internal_shared_this = shared_ptr(dynamic_cast(const_cast(this)), + detail::deleter_wrapper(), detail::ignore_enable_shared_from_this_tag()); + BOOST_ASSERT(_internal_shared_this.get() == this); + _internal_weak_this = _internal_shared_this; + } + } + + typedef T _internal_element_type; // for bcc 5.5.1 + mutable shared_ptr<_internal_element_type> _internal_shared_this; + mutable weak_ptr<_internal_element_type> _internal_weak_this; + mutable bool _owned; protected: - enable_shared_from_this() + enable_shared_from_this(): + _owned(false) { } @@ -38,14 +56,20 @@ return *this; } - ~enable_shared_from_this() +// virtual destructor because we need a vtable for dynamic_cast from base to derived to work + virtual ~enable_shared_from_this() { +// make sure no dangling shared_ptr objects were created by the +// user calling shared_from_this() but never passing ownership of the object +// to a shared_ptr. + BOOST_ASSERT(owned() || _internal_shared_this.unique() || _internal_shared_this == 0); } public: shared_ptr shared_from_this() { + init_internal_shared_once(); shared_ptr p(_internal_weak_this); BOOST_ASSERT(p.get() == this); return p; @@ -53,19 +77,26 @@ shared_ptr shared_from_this() const { + init_internal_shared_once(); shared_ptr p(_internal_weak_this); BOOST_ASSERT(p.get() == this); return p; } -// Note: No, you don't need to initialize _internal_weak_this -// -// Please read the documentation, not the code -// -// http://www.boost.org/libs/smart_ptr/enable_shared_from_this.html + bool owned() const + { + return _owned; + } - typedef T _internal_element_type; // for bcc 5.5.1 - mutable weak_ptr<_internal_element_type> _internal_weak_this; + template + void _internal_accept_owner(shared_ptr &owner) const + { + init_internal_shared_once(); + get_deleter(_internal_shared_this)->set_deleter(owner); + owner = _internal_shared_this; + _internal_shared_this.reset(); + _owned = true; + } }; } // namespace boost Index: boost/shared_ptr.hpp =================================================================== --- boost/shared_ptr.hpp (revision 43733) +++ boost/shared_ptr.hpp (working copy) @@ -48,6 +48,7 @@ namespace boost { +template class shared_ptr; template class weak_ptr; template class enable_shared_from_this; @@ -90,10 +91,15 @@ // enable_shared_from_this support -template void sp_enable_shared_from_this( shared_count const & pn, boost::enable_shared_from_this const * pe, Y const * px ) +struct ignore_enable_shared_from_this_tag {}; + +template void sp_enable_shared_from_this( boost::shared_ptr * ptr, boost::enable_shared_from_this const * pe ) { - if(pe != 0) pe->_internal_weak_this._internal_assign(const_cast(px), pn); + if(pe != 0) + { + pe->_internal_accept_owner(*ptr); } +} #ifdef _MANAGED @@ -104,7 +110,7 @@ template sp_any_pointer( T* ) {} }; -inline void sp_enable_shared_from_this( shared_count const & /*pn*/, sp_any_pointer, sp_any_pointer ) +inline void sp_enable_shared_from_this( sp_any_pointer, sp_any_pointer ) { } @@ -115,7 +121,7 @@ # pragma set woff 3506 #endif -inline void sp_enable_shared_from_this( shared_count const & /*pn*/, ... ) +inline void sp_enable_shared_from_this( ... ) { } @@ -172,7 +178,7 @@ template explicit shared_ptr( Y * p ): px( p ), pn( p ) // Y must be complete { - boost::detail::sp_enable_shared_from_this( pn, p, p ); + boost::detail::sp_enable_shared_from_this( this, p ); } // @@ -183,14 +189,14 @@ template shared_ptr(Y * p, D d): px(p), pn(p, d) { - boost::detail::sp_enable_shared_from_this( pn, p, p ); + boost::detail::sp_enable_shared_from_this( this, p ); } // As above, but with allocator. A's copy constructor shall not throw. template shared_ptr( Y * p, D d, A a ): px( p ), pn( p, d, a ) { - boost::detail::sp_enable_shared_from_this( pn, p, p ); + boost::detail::sp_enable_shared_from_this( this, p ); } // generated copy constructor, assignment, destructor are fine... @@ -253,6 +259,12 @@ } } + // constructor that doesn't trigger enable_shared_from_this code, needed + // for enable_shared_from_this internal implementation + template shared_ptr(Y * p, D d, detail::ignore_enable_shared_from_this_tag tag): + px(p), pn(p, d) + {} + #ifndef BOOST_NO_AUTO_PTR template @@ -260,7 +272,7 @@ { Y * tmp = r.get(); pn = boost::detail::shared_count(r); - boost::detail::sp_enable_shared_from_this( pn, tmp, tmp ); + boost::detail::sp_enable_shared_from_this( this, tmp ); } #if !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) @@ -270,7 +282,7 @@ { typename Ap::element_type * tmp = r.get(); pn = boost::detail::shared_count( r ); - boost::detail::sp_enable_shared_from_this( pn, tmp, tmp ); + boost::detail::sp_enable_shared_from_this( this, tmp ); } @@ -597,6 +609,8 @@ // get_deleter +namespace detail +{ #if ( defined(__GNUC__) && BOOST_WORKAROUND(__GNUC__, < 3) ) || \ ( defined(__EDG_VERSION__) && BOOST_WORKAROUND(__EDG_VERSION__, <= 238) ) || \ ( defined(__HP_aCC) && BOOST_WORKAROUND(__HP_aCC, <= 33500) ) @@ -604,7 +618,7 @@ // g++ 2.9x doesn't allow static_cast(void *) // apparently EDG 2.38 and HP aCC A.03.35 also don't accept it -template D * get_deleter(shared_ptr const & p) +template D * basic_get_deleter(shared_ptr const & p) { void const * q = p._internal_get_deleter(BOOST_SP_TYPEID(D)); return const_cast(static_cast(q)); @@ -612,13 +626,48 @@ #else -template D * get_deleter(shared_ptr const & p) +template D * basic_get_deleter(shared_ptr const & p) { return static_cast(p._internal_get_deleter(BOOST_SP_TYPEID(D))); } #endif +class deleter_wrapper +{ + shared_ptr _deleter; +public: + deleter_wrapper() + {} + void set_deleter(const shared_ptr &deleter) + { + _deleter = deleter; + } + void operator()(const void *) + { + BOOST_ASSERT(_deleter.unique()); + _deleter.reset(); + } + template + D* get_deleter() const + { + return boost::detail::basic_get_deleter(_deleter); + } +}; + +} // namespace detail + +template D * get_deleter(shared_ptr const & p) +{ + D *del = detail::basic_get_deleter(p); + if(del == 0) + { + detail::deleter_wrapper *del_wrapper = detail::basic_get_deleter(p); + if(del_wrapper) del = del_wrapper->get_deleter(); + } + return del; +} + } // namespace boost #ifdef BOOST_MSVC