Sync enable_shared_from_this.hpp and shared_ptr.hpp with release.

[SVN r51485]
This commit is contained in:
Peter Dimov
2009-02-28 20:02:12 +00:00
parent c40b306647
commit 13f91c15f0
2 changed files with 71 additions and 201 deletions

View File

@@ -13,23 +13,15 @@
// http://www.boost.org/libs/smart_ptr/enable_shared_from_this.html // http://www.boost.org/libs/smart_ptr/enable_shared_from_this.html
// //
#include <boost/config.hpp> #include <boost/weak_ptr.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/detail/workaround.hpp> #include <boost/config.hpp>
namespace boost namespace boost
{ {
#if !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS ) template<class T> class enable_shared_from_this
template< class T > class enable_shared_from_this;
template< class T, class Y > void sp_accept_owner( shared_ptr<Y> * ptr, enable_shared_from_this<T> const * pe );
template< class T, class Y > void sp_accept_owner( shared_ptr<Y> * ptr, enable_shared_from_this<T> const * pe, void * /*pd*/ );
#endif
template< class T > class enable_shared_from_this
{ {
protected: protected:
@@ -46,89 +38,36 @@ protected:
return *this; return *this;
} }
// virtual destructor because we need a vtable for dynamic_cast from base to derived to work ~enable_shared_from_this()
virtual ~enable_shared_from_this()
{ {
BOOST_ASSERT( _shared_count.use_count() <= 1 ); // make sure no dangling shared_ptr objects exist
} }
public: public:
shared_ptr<T> shared_from_this() shared_ptr<T> shared_from_this()
{ {
init_weak_once(); shared_ptr<T> p(_internal_weak_this);
T * p = dynamic_cast<T *>( this ); BOOST_ASSERT(p.get() == this);
return shared_ptr<T>( detail::shared_count( _weak_count ), p ); return p;
} }
shared_ptr<T const> shared_from_this() const shared_ptr<T const> shared_from_this() const
{ {
init_weak_once(); shared_ptr<T const> p(_internal_weak_this);
T const * p = dynamic_cast<T const *>( this ); BOOST_ASSERT(p.get() == this);
return shared_ptr<T const>( detail::shared_count( _weak_count ), p ); return p;
} }
private: // 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
mutable detail::weak_count _weak_count; typedef T _internal_element_type; // for bcc 5.5.1
mutable detail::shared_count _shared_count; mutable weak_ptr<_internal_element_type> _internal_weak_this;
void init_weak_once() const
{
if( _weak_count.empty() )
{
detail::shared_count( (void*)0, detail::sp_deleter_wrapper() ).swap( _shared_count );
_weak_count = _shared_count;
}
}
#if !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS )
template< class U, class Y > friend void sp_accept_owner( shared_ptr<Y> * ptr, enable_shared_from_this<U> const * pe );
template< class U, class Y > friend void sp_accept_owner( shared_ptr<Y> * ptr, enable_shared_from_this<U> const * pe, void * /*pd*/ );
#else
public:
#endif
template<typename U>
void sp_accept_owner( shared_ptr<U> & owner ) const
{
if( _weak_count.use_count() == 0 )
{
_weak_count = owner.get_shared_count();
}
else if( !_shared_count.empty() )
{
BOOST_ASSERT( owner.unique() ); // no weak_ptrs to owner should exist either, but there's no way to check that
detail::sp_deleter_wrapper * pd = detail::basic_get_deleter<detail::sp_deleter_wrapper>( _shared_count );
BOOST_ASSERT( pd != 0 );
pd->set_deleter( owner.get_shared_count() );
owner.reset( _shared_count, owner.get() );
detail::shared_count().swap( _shared_count );
}
}
}; };
template< class T, class Y > inline void sp_accept_owner( shared_ptr<Y> * ptr, enable_shared_from_this<T> const * pe )
{
if( pe != 0 )
{
pe->sp_accept_owner( *ptr );
}
}
template< class T, class Y > inline void sp_accept_owner( shared_ptr<Y> * ptr, enable_shared_from_this<T> const * pe, void * /*pd*/ )
{
if( pe != 0 )
{
pe->sp_accept_owner( *ptr );
}
}
} // namespace boost } // namespace boost
#endif // #ifndef BOOST_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED #endif // #ifndef BOOST_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED

View File

@@ -58,8 +58,8 @@
namespace boost namespace boost
{ {
template<class T> class shared_ptr;
template<class T> class weak_ptr; template<class T> class weak_ptr;
template<class T> class enable_shared_from_this;
namespace detail namespace detail
{ {
@@ -98,6 +98,43 @@ template<> struct shared_ptr_traits<void const volatile>
#endif #endif
// enable_shared_from_this support
template<class T, class Y> void sp_enable_shared_from_this( shared_count const & pn, boost::enable_shared_from_this<T> const * pe, Y const * px )
{
if(pe != 0) pe->_internal_weak_this._internal_assign(const_cast<Y*>(px), pn);
}
#ifdef _MANAGED
// Avoid C4793, ... causes native code generation
struct sp_any_pointer
{
template<class T> sp_any_pointer( T* ) {}
};
inline void sp_enable_shared_from_this( shared_count const & /*pn*/, sp_any_pointer, sp_any_pointer )
{
}
#else // _MANAGED
#ifdef sgi
// Turn off: the last argument of the varargs function "sp_enable_shared_from_this" is unnamed
# pragma set woff 3506
#endif
inline void sp_enable_shared_from_this( shared_count const & /*pn*/, ... )
{
}
#ifdef sgi
# pragma reset woff 3506
#endif
#endif // _MANAGED
#if !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) && !defined( BOOST_NO_AUTO_PTR ) #if !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) && !defined( BOOST_NO_AUTO_PTR )
// rvalue auto_ptr support based on a technique by Dave Abrahams // rvalue auto_ptr support based on a technique by Dave Abrahams
@@ -115,32 +152,6 @@ template< class T, class R > struct sp_enable_if_auto_ptr< std::auto_ptr< T >, R
} // namespace detail } // namespace detail
// sp_accept_owner
#ifdef _MANAGED
// Avoid C4793, ... causes native code generation
struct sp_any_pointer
{
template<class T> sp_any_pointer( T* ) {}
};
inline void sp_accept_owner( sp_any_pointer, sp_any_pointer )
{
}
inline void sp_accept_owner( sp_any_pointer, sp_any_pointer, sp_any_pointer )
{
}
#else // _MANAGED
inline void sp_accept_owner( ... )
{
}
#endif // _MANAGED
// //
// shared_ptr // shared_ptr
@@ -171,7 +182,7 @@ public:
template<class Y> template<class Y>
explicit shared_ptr( Y * p ): px( p ), pn( p ) // Y must be complete explicit shared_ptr( Y * p ): px( p ), pn( p ) // Y must be complete
{ {
sp_accept_owner( this, p ); boost::detail::sp_enable_shared_from_this( pn, p, p );
} }
// //
@@ -180,18 +191,16 @@ public:
// shared_ptr will release p by calling d(p) // shared_ptr will release p by calling d(p)
// //
template<class Y, class D> shared_ptr( Y * p, D d ): px( p ), pn( p, d ) template<class Y, class D> shared_ptr(Y * p, D d): px(p), pn(p, d)
{ {
D * pd = static_cast<D *>( pn.get_deleter( BOOST_SP_TYPEID(D) ) ); boost::detail::sp_enable_shared_from_this( pn, p, p );
sp_accept_owner( this, p, pd );
} }
// As above, but with allocator. A's copy constructor shall not throw. // As above, but with allocator. A's copy constructor shall not throw.
template<class Y, class D, class A> shared_ptr( Y * p, D d, A a ): px( p ), pn( p, d, a ) template<class Y, class D, class A> shared_ptr( Y * p, D d, A a ): px( p ), pn( p, d, a )
{ {
D * pd = static_cast<D *>( pn.get_deleter( BOOST_SP_TYPEID(D) ) ); boost::detail::sp_enable_shared_from_this( pn, p, p );
sp_accept_owner( this, p, pd );
} }
// generated copy constructor, assignment, destructor are fine... // generated copy constructor, assignment, destructor are fine...
@@ -238,10 +247,6 @@ public:
{ {
} }
shared_ptr( detail::shared_count const & c, T * p ): px( p ), pn( c ) // never throws
{
}
// aliasing // aliasing
template< class Y > template< class Y >
shared_ptr( shared_ptr<Y> const & r, T * p ): px( p ), pn( r.pn ) // never throws shared_ptr( shared_ptr<Y> const & r, T * p ): px( p ), pn( r.pn ) // never throws
@@ -283,8 +288,7 @@ public:
{ {
Y * tmp = r.get(); Y * tmp = r.get();
pn = boost::detail::shared_count(r); pn = boost::detail::shared_count(r);
boost::detail::sp_enable_shared_from_this( pn, tmp, tmp );
sp_accept_owner( this, tmp );
} }
#if !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) #if !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION )
@@ -294,8 +298,7 @@ public:
{ {
typename Ap::element_type * tmp = r.get(); typename Ap::element_type * tmp = r.get();
pn = boost::detail::shared_count( r ); pn = boost::detail::shared_count( r );
boost::detail::sp_enable_shared_from_this( pn, tmp, tmp );
sp_accept_owner( this, tmp );
} }
@@ -364,10 +367,6 @@ public:
r.px = 0; r.px = 0;
} }
shared_ptr(detail::shared_count && c, T * p): px(p), pn( static_cast< detail::shared_count && >( c ) ) // never throws
{
}
shared_ptr & operator=( shared_ptr && r ) // never throws shared_ptr & operator=( shared_ptr && r ) // never throws
{ {
this_type( static_cast< shared_ptr && >( r ) ).swap( *this ); this_type( static_cast< shared_ptr && >( r ) ).swap( *this );
@@ -409,18 +408,6 @@ public:
this_type( r, p ).swap( *this ); this_type( r, p ).swap( *this );
} }
void reset( detail::shared_count const & c, T * p )
{
this_type( c, p ).swap( *this );
}
#if defined( BOOST_HAS_RVALUE_REFS )
void reset( detail::shared_count && c, T * p )
{
this_type( static_cast< detail::shared_count && >( c ), p ).swap( *this );
}
#endif
reference operator* () const // never throws reference operator* () const // never throws
{ {
BOOST_ASSERT(px != 0); BOOST_ASSERT(px != 0);
@@ -506,16 +493,16 @@ public:
pn.swap(other.pn); pn.swap(other.pn);
} }
detail::shared_count const & get_shared_count() const // never throws
{
return pn;
}
template<class Y> bool _internal_less(shared_ptr<Y> const & rhs) const template<class Y> bool _internal_less(shared_ptr<Y> const & rhs) const
{ {
return pn < rhs.pn; return pn < rhs.pn;
} }
void * _internal_get_deleter( detail::sp_typeinfo const & ti ) const
{
return pn.get_deleter( ti );
}
bool _internal_equiv( shared_ptr const & r ) const bool _internal_equiv( shared_ptr const & r ) const
{ {
return px == r.px && pn == r.pn; return px == r.px && pn == r.pn;
@@ -652,8 +639,6 @@ template<class E, class T, class Y> std::basic_ostream<E, T> & operator<< (std::
// get_deleter // get_deleter
namespace detail
{
#if ( defined(__GNUC__) && BOOST_WORKAROUND(__GNUC__, < 3) ) || \ #if ( defined(__GNUC__) && BOOST_WORKAROUND(__GNUC__, < 3) ) || \
( defined(__EDG_VERSION__) && BOOST_WORKAROUND(__EDG_VERSION__, <= 238) ) || \ ( defined(__EDG_VERSION__) && BOOST_WORKAROUND(__EDG_VERSION__, <= 238) ) || \
( defined(__HP_aCC) && BOOST_WORKAROUND(__HP_aCC, <= 33500) ) ( defined(__HP_aCC) && BOOST_WORKAROUND(__HP_aCC, <= 33500) )
@@ -661,75 +646,21 @@ namespace detail
// g++ 2.9x doesn't allow static_cast<X const *>(void *) // g++ 2.9x doesn't allow static_cast<X const *>(void *)
// apparently EDG 2.38 and HP aCC A.03.35 also don't accept it // apparently EDG 2.38 and HP aCC A.03.35 also don't accept it
template<class D> D * basic_get_deleter(shared_count const & c) template<class D, class T> D * get_deleter(shared_ptr<T> const & p)
{ {
void const * q = c.get_deleter(BOOST_SP_TYPEID(D)); void const * q = p._internal_get_deleter(BOOST_SP_TYPEID(D));
return const_cast<D *>(static_cast<D const *>(q)); return const_cast<D *>(static_cast<D const *>(q));
} }
#else #else
template<class D> D * basic_get_deleter(shared_count const & c) template<class D, class T> D * get_deleter(shared_ptr<T> const & p)
{ {
return static_cast<D *>(c.get_deleter(BOOST_SP_TYPEID(D))); return static_cast<D *>(p._internal_get_deleter(BOOST_SP_TYPEID(D)));
} }
#endif #endif
class sp_deleter_wrapper
{
detail::shared_count _deleter;
public:
sp_deleter_wrapper()
{}
void set_deleter(shared_count const &deleter)
{
_deleter = deleter;
}
void operator()(const void *)
{
BOOST_ASSERT(_deleter.use_count() <= 1);
detail::shared_count().swap( _deleter );
}
template<typename D>
#if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, < 1300 )
D* get_deleter( D* ) const
#else
D* get_deleter() const
#endif
{
return boost::detail::basic_get_deleter<D>(_deleter);
}
};
} // namespace detail
template<class D, class T> D * get_deleter( shared_ptr<T> const & p )
{
D *del = detail::basic_get_deleter<D>( p.get_shared_count() );
if( del == 0 )
{
detail::sp_deleter_wrapper *del_wrapper = detail::basic_get_deleter<detail::sp_deleter_wrapper>(p.get_shared_count());
#if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, < 1300 )
if( del_wrapper ) del = del_wrapper->get_deleter( (D*)0 );
#elif defined( __GNUC__ ) && BOOST_WORKAROUND( __GNUC__, < 4 )
if( del_wrapper ) del = del_wrapper->::boost::detail::sp_deleter_wrapper::get_deleter<D>();
#else
if( del_wrapper ) del = del_wrapper->get_deleter<D>();
#endif
}
return del;
}
// atomic access // atomic access
#if !defined(BOOST_SP_NO_ATOMIC_ACCESS) #if !defined(BOOST_SP_NO_ATOMIC_ACCESS)