diff --git a/include/boost/smart_ptr/enable_shared_from_this.hpp b/include/boost/smart_ptr/enable_shared_from_this.hpp index ed9aadd..f7b1445 100644 --- a/include/boost/smart_ptr/enable_shared_from_this.hpp +++ b/include/boost/smart_ptr/enable_shared_from_this.hpp @@ -4,11 +4,11 @@ // // enable_shared_from_this.hpp // -// Copyright (c) 2002 Peter Dimov +// Copyright 2002, 2009 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) +// 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 // // http://www.boost.org/libs/smart_ptr/enable_shared_from_this.html // @@ -46,26 +46,32 @@ public: shared_ptr shared_from_this() { - shared_ptr p(_internal_weak_this); - BOOST_ASSERT(p.get() == this); + shared_ptr p( weak_this_ ); + BOOST_ASSERT( p.get() == this ); return p; } shared_ptr shared_from_this() const { - shared_ptr p(_internal_weak_this); - BOOST_ASSERT(p.get() == this); + shared_ptr p( 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 +public: // actually private, but avoids compiler template friendship issues - typedef T _internal_element_type; // for bcc 5.5.1 - mutable weak_ptr<_internal_element_type> _internal_weak_this; + // Note: invoked automatically by shared_ptr; do not call + template void _internal_accept_owner( shared_ptr const * ppx, Y * py ) const + { + if( weak_this_.expired() ) + { + weak_this_ = shared_ptr( *ppx, py ); + } + } + +private: + + mutable weak_ptr weak_this_; }; } // namespace boost diff --git a/include/boost/smart_ptr/make_shared.hpp b/include/boost/smart_ptr/make_shared.hpp index 25b9cf0..7e1e793 100644 --- a/include/boost/smart_ptr/make_shared.hpp +++ b/include/boost/smart_ptr/make_shared.hpp @@ -105,10 +105,13 @@ template< class T > boost::shared_ptr< T > make_shared() void * pv = pd->address(); - new( pv ) T(); + ::new( pv ) T(); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A > boost::shared_ptr< T > allocate_shared( A const & a ) @@ -119,10 +122,13 @@ template< class T, class A > boost::shared_ptr< T > allocate_shared( A const & a void * pv = pd->address(); - new( pv ) T(); + ::new( pv ) T(); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } #if defined( BOOST_HAS_VARIADIC_TMPL ) && defined( BOOST_HAS_RVALUE_REFS ) @@ -137,10 +143,13 @@ template< class T, class... Args > boost::shared_ptr< T > make_shared( Args && . void * pv = pd->address(); - new( pv ) T( detail::forward( args )... ); + ::new( pv ) T( detail::forward( args )... ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A, class... Args > boost::shared_ptr< T > allocate_shared( A const & a, Args && ... args ) @@ -151,10 +160,13 @@ template< class T, class A, class... Args > boost::shared_ptr< T > allocate_shar void * pv = pd->address(); - new( pv ) T( detail::forward( args )... ); + ::new( pv ) T( detail::forward( args )... ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } #else @@ -170,10 +182,13 @@ boost::shared_ptr< T > make_shared( A1 const & a1 ) void * pv = pd->address(); - new( pv ) T( a1 ); + ::new( pv ) T( a1 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A, class A1 > @@ -185,10 +200,13 @@ boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1 ) void * pv = pd->address(); - new( pv ) T( a1 ); + ::new( pv ) T( a1 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A1, class A2 > @@ -200,10 +218,13 @@ boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2 ) void * pv = pd->address(); - new( pv ) T( a1, a2 ); + ::new( pv ) T( a1, a2 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A, class A1, class A2 > @@ -215,10 +236,13 @@ boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a void * pv = pd->address(); - new( pv ) T( a1, a2 ); + ::new( pv ) T( a1, a2 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A1, class A2, class A3 > @@ -230,10 +254,13 @@ boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3 void * pv = pd->address(); - new( pv ) T( a1, a2, a3 ); + ::new( pv ) T( a1, a2, a3 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A, class A1, class A2, class A3 > @@ -245,10 +272,13 @@ boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a void * pv = pd->address(); - new( pv ) T( a1, a2, a3 ); + ::new( pv ) T( a1, a2, a3 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A1, class A2, class A3, class A4 > @@ -260,10 +290,13 @@ boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3, void * pv = pd->address(); - new( pv ) T( a1, a2, a3, a4 ); + ::new( pv ) T( a1, a2, a3, a4 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A, class A1, class A2, class A3, class A4 > @@ -275,10 +308,13 @@ boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a void * pv = pd->address(); - new( pv ) T( a1, a2, a3, a4 ); + ::new( pv ) T( a1, a2, a3, a4 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A1, class A2, class A3, class A4, class A5 > @@ -290,10 +326,13 @@ boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3, void * pv = pd->address(); - new( pv ) T( a1, a2, a3, a4, a5 ); + ::new( pv ) T( a1, a2, a3, a4, a5 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A, class A1, class A2, class A3, class A4, class A5 > @@ -305,10 +344,13 @@ boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a void * pv = pd->address(); - new( pv ) T( a1, a2, a3, a4, a5 ); + ::new( pv ) T( a1, a2, a3, a4, a5 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A1, class A2, class A3, class A4, class A5, class A6 > @@ -320,10 +362,13 @@ boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3, void * pv = pd->address(); - new( pv ) T( a1, a2, a3, a4, a5, a6 ); + ::new( pv ) T( a1, a2, a3, a4, a5, a6 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6 > @@ -335,10 +380,13 @@ boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a void * pv = pd->address(); - new( pv ) T( a1, a2, a3, a4, a5, a6 ); + ::new( pv ) T( a1, a2, a3, a4, a5, a6 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7 > @@ -350,10 +398,13 @@ boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3, void * pv = pd->address(); - new( pv ) T( a1, a2, a3, a4, a5, a6, a7 ); + ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6, class A7 > @@ -365,10 +416,13 @@ boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a void * pv = pd->address(); - new( pv ) T( a1, a2, a3, a4, a5, a6, a7 ); + ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8 > @@ -380,10 +434,13 @@ boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3, void * pv = pd->address(); - new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8 ); + ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8 > @@ -395,10 +452,13 @@ boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a void * pv = pd->address(); - new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8 ); + ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9 > @@ -410,10 +470,13 @@ boost::shared_ptr< T > make_shared( A1 const & a1, A2 const & a2, A3 const & a3, void * pv = pd->address(); - new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); + ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9 > @@ -425,10 +488,13 @@ boost::shared_ptr< T > allocate_shared( A const & a, A1 const & a1, A2 const & a void * pv = pd->address(); - new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); + ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); pd->set_initialized(); - return boost::shared_ptr< T >( pt, static_cast< T* >( pv ) ); + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); } #endif diff --git a/include/boost/smart_ptr/shared_ptr.hpp b/include/boost/smart_ptr/shared_ptr.hpp index c7cdaf7..0812c04 100644 --- a/include/boost/smart_ptr/shared_ptr.hpp +++ b/include/boost/smart_ptr/shared_ptr.hpp @@ -58,6 +58,7 @@ namespace boost { +template class shared_ptr; template class weak_ptr; template class enable_shared_from_this; @@ -100,9 +101,12 @@ template<> struct shared_ptr_traits // 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 ) +template< class X, class Y, class T > inline void sp_enable_shared_from_this( boost::shared_ptr const * ppx, Y const * py, boost::enable_shared_from_this< T > const * pe ) { - if(pe != 0) pe->_internal_weak_this._internal_assign(const_cast(px), pn); + if( pe != 0 ) + { + pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) ); + } } #ifdef _MANAGED @@ -114,25 +118,16 @@ struct sp_any_pointer 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, 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*/, ... ) +inline void sp_enable_shared_from_this( ... ) { } -#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 ) @@ -182,7 +177,7 @@ public: 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, p ); } // @@ -193,14 +188,14 @@ public: 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, 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, p ); } // generated copy constructor, assignment, destructor are fine... @@ -288,7 +283,7 @@ public: { 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, tmp ); } #if !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) @@ -298,7 +293,7 @@ public: { 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, tmp ); } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 5f68e20..34cd5f1 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -48,5 +48,9 @@ import testing ; [ run ip_convertible_test.cpp ] [ run allocate_shared_test.cpp ] [ run sp_atomic_test.cpp ] + [ run esft_void_test.cpp ] + [ run esft_second_ptr_test.cpp ] + [ run make_shared_esft_test.cpp ] + [ run allocate_shared_esft_test.cpp ] ; } diff --git a/test/allocate_shared_esft_test.cpp b/test/allocate_shared_esft_test.cpp new file mode 100644 index 0000000..2bb8ccc --- /dev/null +++ b/test/allocate_shared_esft_test.cpp @@ -0,0 +1,264 @@ +// allocate_shared_esft_test.cpp +// +// Copyright 2007-2009 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 +#include +#include +#include +#include + +class X: public boost::enable_shared_from_this +{ +private: + + X( X const & ); + X & operator=( X const & ); + +public: + + static int instances; + + explicit X( int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0 ) + { + ++instances; + } + + ~X() + { + --instances; + } +}; + +int X::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator() ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2, 3 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4, 5 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7, 8 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7, 8, 9 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + return boost::report_errors(); +} diff --git a/test/allocate_shared_test.cpp b/test/allocate_shared_test.cpp index 71ee948..97808c2 100644 --- a/test/allocate_shared_test.cpp +++ b/test/allocate_shared_test.cpp @@ -10,6 +10,7 @@ #include #include #include +#include class X { @@ -18,6 +19,14 @@ private: X( X const & ); X & operator=( X const & ); + void * operator new( std::size_t ); + + void operator delete( void * p ) + { + // lack of this definition causes link errors on MSVC + ::operator delete( p ); + } + public: static int instances; diff --git a/test/esft_constructor_test.cpp b/test/esft_constructor_test.cpp deleted file mode 100644 index 737123e..0000000 --- a/test/esft_constructor_test.cpp +++ /dev/null @@ -1,169 +0,0 @@ -// -// 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 -#include -#include -#include -#include - -class X: public boost::enable_shared_from_this< 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 *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 -bool are_shared_owners(const boost::shared_ptr &a, const boost::shared_ptr &b) -{ - return !(a < b) && !(b < a); -} - -struct Y: public boost::enable_shared_from_this -{}; - -int main() -{ - BOOST_TEST( X::instances == 0 ); - - { - boost::shared_ptr early_px; - X* x = new X( 1, &early_px ); - BOOST_TEST( early_px.use_count() > 0 ); - BOOST_TEST( boost::get_deleter(early_px) == 0 ); - boost::shared_ptr 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(early_px); - BOOST_TEST(pd && *pd == &X::deleter2 ); - } - - BOOST_TEST( X::instances == 0 ); - - { - boost::shared_ptr early_px; - X* x = new X( 1, &early_px ); - boost::weak_ptr early_weak_px = early_px; - early_px.reset(); - BOOST_TEST( !early_weak_px.expired() ); - boost::shared_ptr 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 early_px; - X x( 1, &early_px ); - BOOST_TEST( early_px.use_count() > 0 ); - boost::shared_ptr 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 &err) - {} - } - - BOOST_TEST( X::instances == 0 ); - - { - boost::weak_ptr early_weak_px; - { - boost::shared_ptr 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 px(new Y()); - Y y(*px); - px.reset(); - try - { - y.shared_from_this(); - } - catch( const boost::bad_weak_ptr &err) - { - BOOST_ERROR("y threw bad_weak_ptr"); - } - } - - return boost::report_errors(); -} diff --git a/test/esft_second_ptr_test.cpp b/test/esft_second_ptr_test.cpp new file mode 100644 index 0000000..0600667 --- /dev/null +++ b/test/esft_second_ptr_test.cpp @@ -0,0 +1,51 @@ +// +// esft_second_ptr_test.cpp +// +// This test has been extracted from a real +// scenario that occurs in Boost.Python +// +// Copyright 2009 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 +#include +#include + +// + +class X: public boost::enable_shared_from_this +{ +}; + +void null_deleter( void const* ) +{ +} + +int main() +{ + boost::shared_ptr px( new X ); + + { + boost::shared_ptr px2( px.get(), null_deleter ); + BOOST_TEST( px == px2 ); + } + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + + return boost::report_errors(); +} diff --git a/test/esft_void_test.cpp b/test/esft_void_test.cpp new file mode 100644 index 0000000..b28c669 --- /dev/null +++ b/test/esft_void_test.cpp @@ -0,0 +1,41 @@ +// +// esft_void_test.cpp +// +// Copyright 2009 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 +#include +#include + +// + +class X: public boost::enable_shared_from_this +{ +}; + +int main() +{ + boost::shared_ptr< void const volatile > pv( new X ); + boost::shared_ptr< void > pv2 = boost::const_pointer_cast< void >( pv ); + boost::shared_ptr< X > px = boost::static_pointer_cast< X >( pv2 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + + return boost::report_errors(); +} diff --git a/test/make_shared_esft_test.cpp b/test/make_shared_esft_test.cpp new file mode 100644 index 0000000..1956cba --- /dev/null +++ b/test/make_shared_esft_test.cpp @@ -0,0 +1,263 @@ +// make_shared_esft_test.cpp +// +// Copyright 2007-2009 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 +#include +#include +#include + +class X: public boost::enable_shared_from_this +{ +private: + + X( X const & ); + X & operator=( X const & ); + +public: + + static int instances; + + explicit X( int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0 ) + { + ++instances; + } + + ~X() + { + --instances; + } +}; + +int X::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >(); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2, 3 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2, 3, 4 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2, 3, 4, 5 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2, 3, 4, 5, 6 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2, 3, 4, 5, 6, 7 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2, 3, 4, 5, 6, 7, 8 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_shared< X >( 1, 2, 3, 4, 5, 6, 7, 8, 9 ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + + return boost::report_errors(); +} diff --git a/test/make_shared_test.cpp b/test/make_shared_test.cpp index 9930e31..474d1c5 100644 --- a/test/make_shared_test.cpp +++ b/test/make_shared_test.cpp @@ -10,6 +10,7 @@ #include #include #include +#include class X { @@ -18,6 +19,14 @@ private: X( X const & ); X & operator=( X const & ); + void * operator new( std::size_t ); + + void operator delete( void * p ) + { + // lack of this definition causes link errors on MSVC + ::operator delete( p ); + } + public: static int instances; diff --git a/test/shared_from_this_test.cpp b/test/shared_from_this_test.cpp index 61515bd..68d6098 100644 --- a/test/shared_from_this_test.cpp +++ b/test/shared_from_this_test.cpp @@ -55,16 +55,23 @@ void test() BOOST_TEST(py.get() != 0); BOOST_TEST(py.use_count() == 1); - boost::shared_ptr px = py->getX(); - BOOST_TEST(px.get() != 0); - BOOST_TEST(py.use_count() == 2); + try + { + boost::shared_ptr px = py->getX(); + BOOST_TEST(px.get() != 0); + BOOST_TEST(py.use_count() == 2); - px->f(); + px->f(); - boost::shared_ptr py2 = boost::dynamic_pointer_cast(px); - BOOST_TEST(py.get() == py2.get()); - BOOST_TEST(!(py < py2 || py2 < py)); - BOOST_TEST(py.use_count() == 3); + boost::shared_ptr py2 = boost::dynamic_pointer_cast(px); + BOOST_TEST(py.get() == py2.get()); + BOOST_TEST(!(py < py2 || py2 < py)); + BOOST_TEST(py.use_count() == 3); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "py->getX() failed" ); + } } void test2(); @@ -124,19 +131,25 @@ void test3() { boost::shared_ptr p(new V); - boost::shared_ptr q = p->shared_from_this(); - BOOST_TEST(p == q); - BOOST_TEST(!(p < q) && !(q < p)); + try + { + boost::shared_ptr q = p->shared_from_this(); + BOOST_TEST(p == q); + BOOST_TEST(!(p < q) && !(q < p)); + } + catch( boost::bad_weak_ptr const & ) + { + BOOST_ERROR( "p->shared_from_this() failed" ); + } V v2(*p); try { boost::shared_ptr r = v2.shared_from_this(); - BOOST_TEST( p < r || r < p ); - BOOST_TEST( r.get() == &v2 ); + BOOST_ERROR("v2.shared_from_this() failed to throw"); } - catch(boost::bad_weak_ptr const &) + catch( boost::bad_weak_ptr const & ) { } @@ -147,7 +160,7 @@ void test3() BOOST_TEST(p == r); BOOST_TEST(!(p < r) && !(r < p)); } - catch(boost::bad_weak_ptr const &) + catch( boost::bad_weak_ptr const & ) { BOOST_ERROR("p->shared_from_this() threw bad_weak_ptr after *p = V()"); } diff --git a/test/shared_ptr_move_test.cpp b/test/shared_ptr_move_test.cpp index 8814d3d..bd785e4 100644 --- a/test/shared_ptr_move_test.cpp +++ b/test/shared_ptr_move_test.cpp @@ -8,6 +8,8 @@ // http://www.boost.org/LICENSE_1_0.txt // +#if defined( BOOST_HAS_RVALUE_REFS ) + #include #include @@ -93,3 +95,12 @@ int main() return boost::report_errors(); } + +#else // !defined( BOOST_HAS_RVALUE_REFS ) + +int main() +{ + return 0; +} + +#endif diff --git a/test/sp_accept_owner_test.cpp b/test/sp_accept_owner_test.cpp deleted file mode 100644 index e8d1b32..0000000 --- a/test/sp_accept_owner_test.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// -// sp_accept_owner_test.cpp -// -// 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 -#include -#include - -namespace N -{ - -struct D; - -struct X -{ - X * px_; - - D * pd_; - void * pv_; - - X(): px_( 0 ), pd_( 0 ), pv_( 0 ) - { - } -}; - -struct D -{ - template void operator()( T * p ) const { delete p; } -}; - -} // namespace N - -#if !defined( BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP ) - -namespace N -{ - -#else - -namespace boost -{ - -#endif - -template inline void sp_accept_owner( boost::shared_ptr * ps, ::N::X * px ) -{ - std::cout << "sp_accept_owner( " << ps << ", " << px << " )\n"; - - BOOST_TEST( ps->get() == px ); - - if( px != 0 ) - { - px->px_ = px; - } -} - -template inline void sp_accept_owner( boost::shared_ptr * ps, ::N::X * px, ::N::D * pd ) -{ - std::cout << "sp_accept_owner( " << ps << ", " << px << ", (D*)" << pd << " )\n"; - - BOOST_TEST( ps->get() == px ); - - if( px != 0 ) - { - px->px_ = px; - px->pd_ = pd; - } -} - -template inline void sp_accept_owner( boost::shared_ptr * ps, ::N::X * px, void * pv ) -{ - std::cout << "sp_accept_owner( " << ps << ", " << px << ", (void*)" << pv << " )\n"; - - BOOST_TEST( ps->get() == px ); - - if( px != 0 ) - { - px->px_ = px; - px->pv_ = pv; - } -} - -} // namespace N or boost - -struct D2 -{ - template void operator()( T * p ) const { delete p; } -}; - -template void test( T* = 0 ) -{ - { - boost::shared_ptr p( static_cast< T* >( 0 ) ); - } - - { - T * p = new T; - boost::shared_ptr q( p ); - - BOOST_TEST( q->px_ == p ); - BOOST_TEST( q->pd_ == 0 ); - BOOST_TEST( q->pv_ == 0 ); - } - - { - T * p = new T; - boost::shared_ptr q( p, N::D() ); - - BOOST_TEST( q->px_ == p ); - BOOST_TEST( q->pd_ != 0 ); - BOOST_TEST( q->pv_ == 0 ); - } - - { - T * p = new T; - boost::shared_ptr q( p, D2() ); - - BOOST_TEST( q->px_ == p ); - BOOST_TEST( q->pd_ == 0 ); - BOOST_TEST( q->pv_ != 0 ); - } -} - -namespace N2 -{ - -struct Y: public virtual N::X -{ -}; - -} // namespace N2 - -int main() -{ - test(); - test(); - - return boost::report_errors(); -}