From 22f1b092c90efe89f19636c90b84c23b60a66fdd Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 5 Mar 2009 23:06:17 +0000 Subject: [PATCH] Merge [51581] to release. Fixes #2126. Fixes #2584. [SVN r51632] --- .../smart_ptr/enable_shared_from_this.hpp | 36 ++- include/boost/smart_ptr/make_shared.hpp | 154 +++++++--- include/boost/smart_ptr/shared_ptr.hpp | 31 +- test/Jamfile.v2 | 4 + test/allocate_shared_esft_test.cpp | 264 ++++++++++++++++++ test/allocate_shared_test.cpp | 9 + test/esft_second_ptr_test.cpp | 51 ++++ test/esft_void_test.cpp | 41 +++ test/make_shared_esft_test.cpp | 263 +++++++++++++++++ test/make_shared_test.cpp | 9 + test/shared_from_this_test.cpp | 43 ++- test/shared_ptr_move_test.cpp | 11 + 12 files changed, 824 insertions(+), 92 deletions(-) create mode 100644 test/allocate_shared_esft_test.cpp create mode 100644 test/esft_second_ptr_test.cpp create mode 100644 test/esft_void_test.cpp create mode 100644 test/make_shared_esft_test.cpp 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_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