Bring back the constructor-enabled enable_shared_from_this as enable_shared_from_this2.

[SVN r51912]
This commit is contained in:
Peter Dimov
2009-03-22 21:11:17 +00:00
parent 6f2bdddfa0
commit d34d638998
5 changed files with 254 additions and 72 deletions

View File

@ -1,16 +1,15 @@
#ifndef BOOST_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED #ifndef BOOST_ENABLE_SHARED_FROM_THIS2_HPP_INCLUDED
#define BOOST_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED #define BOOST_ENABLE_SHARED_FROM_THIS2_HPP_INCLUDED
// //
// enable_shared_from_this.hpp // enable_shared_from_this2.hpp
// //
// Copyright (c) 2002 Peter Dimov // Copyright 2002, 2009 Peter Dimov
// Copyright 2008 Frank Mori Hess
// //
// Distributed under the Boost Software License, Version 1.0. (See // Distributed under the Boost Software License, Version 1.0.
// accompanying file LICENSE_1_0.txt or copy at // See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt
//
// http://www.boost.org/libs/smart_ptr/enable_shared_from_this.html
// //
#include <boost/config.hpp> #include <boost/config.hpp>
@ -21,114 +20,113 @@
namespace boost namespace boost
{ {
#if !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS ) namespace detail
{
template< class T > class enable_shared_from_this; class esft2_deleter_wrapper
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*/ ); private:
#endif shared_ptr<void> deleter_;
template< class T > class enable_shared_from_this public:
esft2_deleter_wrapper()
{
}
template< class T > void set_deleter( shared_ptr<T> const & deleter )
{
deleter_ = deleter;
}
template< class T> void operator()( T* )
{
BOOST_ASSERT( deleter_.use_count() <= 1 );
deleter_.reset();
}
};
} // namespace detail
template< class T > class enable_shared_from_this2
{ {
protected: protected:
enable_shared_from_this() enable_shared_from_this2()
{ {
} }
enable_shared_from_this(enable_shared_from_this const &) enable_shared_from_this2( enable_shared_from_this2 const & )
{ {
} }
enable_shared_from_this & operator=(enable_shared_from_this const &) enable_shared_from_this2 & operator=( enable_shared_from_this2 const & )
{ {
return *this; return *this;
} }
// virtual destructor because we need a vtable for dynamic_cast from base to derived to work ~enable_shared_from_this2()
virtual ~enable_shared_from_this()
{ {
BOOST_ASSERT( _shared_count.use_count() <= 1 ); // make sure no dangling shared_ptr objects exist BOOST_ASSERT( shared_this_.use_count() <= 1 ); // make sure no dangling shared_ptr objects exist
} }
private:
mutable weak_ptr<T> weak_this_;
mutable shared_ptr<T> shared_this_;
public: public:
shared_ptr<T> shared_from_this() shared_ptr<T> shared_from_this()
{ {
init_weak_once(); init_weak_once();
T * p = dynamic_cast<T *>( this ); return shared_ptr<T>( weak_this_ );
return shared_ptr<T>( detail::shared_count( _weak_count ), p );
} }
shared_ptr<T const> shared_from_this() const shared_ptr<T const> shared_from_this() const
{ {
init_weak_once(); init_weak_once();
T const * p = dynamic_cast<T const *>( this ); return shared_ptr<T>( weak_this_ );
return shared_ptr<T const>( detail::shared_count( _weak_count ), p );
} }
private: private:
mutable detail::weak_count _weak_count;
mutable detail::shared_count _shared_count;
void init_weak_once() const void init_weak_once() const
{ {
if( _weak_count.empty() ) if( weak_this_._empty() )
{ {
detail::shared_count( (void*)0, detail::sp_deleter_wrapper() ).swap( _shared_count ); shared_this_.reset( static_cast< T* >( 0 ), detail::esft2_deleter_wrapper() );
_weak_count = _shared_count; weak_this_ = shared_this_;
} }
} }
#if !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS ) public: // actually private, but avoids compiler template friendship issues
template< class U, class Y > friend void sp_accept_owner( shared_ptr<Y> * ptr, enable_shared_from_this<U> const * pe ); // Note: invoked automatically by shared_ptr; do not call
template< class U, class Y > friend void sp_accept_owner( shared_ptr<Y> * ptr, enable_shared_from_this<U> const * pe, void * /*pd*/ ); template<class X, class Y> void _internal_accept_owner( shared_ptr<X> * ppx, Y * py ) const
#else
public:
#endif
template<typename U>
void sp_accept_owner( shared_ptr<U> & owner ) const
{ {
if( _weak_count.use_count() == 0 ) BOOST_ASSERT( ppx != 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() ); if( weak_this_.use_count() == 0 )
detail::shared_count().swap( _shared_count ); {
weak_this_ = shared_ptr<T>( *ppx, py );
}
else if( shared_this_.use_count() != 0 )
{
BOOST_ASSERT( ppx->unique() ); // no weak_ptrs should exist either, but there's no way to check that
detail::esft2_deleter_wrapper * pd = boost::get_deleter<detail::esft2_deleter_wrapper>( shared_this_ );
BOOST_ASSERT( pd != 0 );
pd->set_deleter( *ppx );
ppx->reset( shared_this_, ppx->get() );
shared_this_.reset();
} }
} }
}; };
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_THIS2_HPP_INCLUDED

View File

@ -61,6 +61,7 @@ namespace boost
template<class T> class shared_ptr; 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; template<class T> class enable_shared_from_this;
template<class T> class enable_shared_from_this2;
namespace detail namespace detail
{ {
@ -109,6 +110,14 @@ template< class X, class Y, class T > inline void sp_enable_shared_from_this( bo
} }
} }
template< class X, class Y, class T > inline void sp_enable_shared_from_this( boost::shared_ptr<X> * ppx, Y const * py, boost::enable_shared_from_this2< T > const * pe )
{
if( pe != 0 )
{
pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) );
}
}
#ifdef _MANAGED #ifdef _MANAGED
// Avoid C4793, ... causes native code generation // Avoid C4793, ... causes native code generation

View File

@ -124,6 +124,11 @@ public:
return pn.use_count() == 0; return pn.use_count() == 0;
} }
bool _empty() const // extension, not in std::weak_ptr
{
return pn.empty();
}
void reset() // never throws in 1.30+ void reset() // never throws in 1.30+
{ {
this_type().swap(*this); this_type().swap(*this);

View File

@ -56,5 +56,6 @@ import testing ;
[ run sp_recursive_assign2_test.cpp ] [ run sp_recursive_assign2_test.cpp ]
[ run sp_recursive_assign_rv_test.cpp ] [ run sp_recursive_assign_rv_test.cpp ]
[ run sp_recursive_assign2_rv_test.cpp ] [ run sp_recursive_assign2_rv_test.cpp ]
[ run esft_constructor_test.cpp ]
; ;
} }

View File

@ -0,0 +1,169 @@
//
// esft_constructor_test.cpp
//
// A test for the new enable_shared_from_this support for calling
// shared_from_this from constructors (that is, prior to the
// object's ownership being passed to an external shared_ptr).
//
// Copyright (c) 2008 Frank Mori Hess
// Copyright (c) 2008 Peter Dimov
//
// Distributed under the Boost Software License, Version 1.0.
//
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#include <boost/smart_ptr/enable_shared_from_this2.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <memory>
class X: public boost::enable_shared_from_this2< X >
{
private:
int destroyed_;
int deleted_;
int expected_;
private:
X( X const& );
X& operator=( X const& );
public:
static int instances;
public:
explicit X( int expected, boost::shared_ptr<X> *early_px = 0 ): destroyed_( 0 ), deleted_( 0 ), expected_( expected )
{
++instances;
if( early_px ) *early_px = shared_from_this();
}
~X()
{
BOOST_TEST( deleted_ == expected_ );
BOOST_TEST( destroyed_ == 0 );
++destroyed_;
--instances;
}
typedef void (*deleter_type)( X* );
static void deleter( X * px )
{
++px->deleted_;
}
static void deleter2( X * px )
{
++px->deleted_;
delete px;
}
};
int X::instances = 0;
template<typename T, typename U>
bool are_shared_owners(const boost::shared_ptr<T> &a, const boost::shared_ptr<U> &b)
{
return !(a < b) && !(b < a);
}
struct Y: public boost::enable_shared_from_this2<Y>
{};
int main()
{
BOOST_TEST( X::instances == 0 );
{
boost::shared_ptr<X> early_px;
X* x = new X( 1, &early_px );
BOOST_TEST( early_px.use_count() > 0 );
BOOST_TEST( boost::get_deleter<X::deleter_type>(early_px) == 0 );
boost::shared_ptr<X> px( x, &X::deleter2 );
BOOST_TEST( early_px.use_count() == 2 && px.use_count() == 2 );
BOOST_TEST(are_shared_owners(early_px, px));
px.reset();
BOOST_TEST( early_px.use_count() == 1 );
BOOST_TEST( X::instances == 1 );
// X::deleter_type *pd = boost::get_deleter<X::deleter_type>(early_px);
// BOOST_TEST(pd && *pd == &X::deleter2 );
}
BOOST_TEST( X::instances == 0 );
{
boost::shared_ptr<X> early_px;
X* x = new X( 1, &early_px );
boost::weak_ptr<X> early_weak_px = early_px;
early_px.reset();
BOOST_TEST( !early_weak_px.expired() );
boost::shared_ptr<X> px( x, &X::deleter2 );
BOOST_TEST( px.use_count() == 1 );
BOOST_TEST( X::instances == 1 );
BOOST_TEST(are_shared_owners(early_weak_px.lock(), px));
px.reset();
BOOST_TEST( early_weak_px.expired() );
}
BOOST_TEST( X::instances == 0 );
{
boost::shared_ptr<X> early_px;
X x( 1, &early_px );
BOOST_TEST( early_px.use_count() > 0 );
boost::shared_ptr<X> px( &x, &X::deleter );
BOOST_TEST( early_px.use_count() == 2 && px.use_count() == 2 );
early_px.reset();
BOOST_TEST( px.use_count() == 1 );
BOOST_TEST( X::instances == 1 );
px.reset();
try
{
x.shared_from_this();
BOOST_ERROR("x did not throw bad_weak_ptr");
}
catch( const boost::bad_weak_ptr & )
{}
}
BOOST_TEST( X::instances == 0 );
{
boost::weak_ptr<X> early_weak_px;
{
boost::shared_ptr<X> early_px;
X x( 0, &early_px );
early_weak_px = early_px;
early_px.reset();
BOOST_TEST( !early_weak_px.expired() );
BOOST_TEST( X::instances == 1 );
}
BOOST_TEST( early_weak_px.expired() );
}
BOOST_TEST( X::instances == 0 );
{
boost::shared_ptr<Y> px(new Y());
Y y(*px);
px.reset();
try
{
y.shared_from_this();
}
catch( const boost::bad_weak_ptr & )
{
BOOST_ERROR("y threw bad_weak_ptr");
}
}
return boost::report_errors();
}