diff --git a/include/boost/smart_ptr/detail/local_counted_base.hpp b/include/boost/smart_ptr/detail/local_counted_base.hpp index 20ba3c2..85bfd52 100644 --- a/include/boost/smart_ptr/detail/local_counted_base.hpp +++ b/include/boost/smart_ptr/detail/local_counted_base.hpp @@ -57,6 +57,8 @@ public: virtual void destroy() BOOST_SP_NOEXCEPT = 0; + virtual boost::shared_ptr get_shared_ptr() const BOOST_SP_NOEXCEPT = 0; + void add_ref() BOOST_SP_NOEXCEPT { #if defined( __has_builtin ) @@ -114,6 +116,11 @@ public: { delete this; } + + virtual boost::shared_ptr get_shared_ptr() const BOOST_SP_NOEXCEPT + { + return const_pointer_cast( pn_ ); + } }; class local_counted_impl_em: public local_counted_base @@ -126,6 +133,11 @@ public: { pn_.reset(); } + + virtual boost::shared_ptr get_shared_ptr() const BOOST_SP_NOEXCEPT + { + return const_pointer_cast( pn_ ); + } }; } // namespace detail diff --git a/include/boost/smart_ptr/local_shared_ptr.hpp b/include/boost/smart_ptr/local_shared_ptr.hpp index b2566b5..9ca464b 100644 --- a/include/boost/smart_ptr/local_shared_ptr.hpp +++ b/include/boost/smart_ptr/local_shared_ptr.hpp @@ -437,6 +437,36 @@ public: return pn? pn->local_use_count(): 0; } + // conversions to shared_ptr, weak_ptr + + template operator shared_ptr() const BOOST_SP_NOEXCEPT + { + boost::detail::sp_assert_convertible(); + + if( pn ) + { + return static_pointer_cast( pn->get_shared_ptr() ); + } + else + { + return shared_ptr(); + } + } + + template operator weak_ptr() const BOOST_SP_NOEXCEPT + { + boost::detail::sp_assert_convertible(); + + if( pn ) + { + return static_pointer_cast( pn->get_shared_ptr() ); + } + else + { + return weak_ptr(); + } + } + // swap void swap( local_shared_ptr & r ) BOOST_SP_NOEXCEPT @@ -487,6 +517,31 @@ template inline bool operator!=( boost::detail::sp_nullptr_t, local_sha #endif +template inline bool operator==( local_shared_ptr const & a, shared_ptr const & b ) BOOST_SP_NOEXCEPT +{ + return a.get() == b.get(); +} + +template inline bool operator!=( local_shared_ptr const & a, shared_ptr const & b ) BOOST_SP_NOEXCEPT +{ + return a.get() != b.get(); +} + +template inline bool operator==( shared_ptr const & a, local_shared_ptr const & b ) BOOST_SP_NOEXCEPT +{ + return a.get() == b.get(); +} + +template inline bool operator!=( shared_ptr const & a, local_shared_ptr const & b ) BOOST_SP_NOEXCEPT +{ + return a.get() != b.get(); +} + +template inline bool operator<(local_shared_ptr const & a, local_shared_ptr const & b) BOOST_SP_NOEXCEPT +{ + return a.owner_before( b ); +} + template inline void swap( local_shared_ptr & a, local_shared_ptr & b ) BOOST_SP_NOEXCEPT { a.swap( b ); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index f5b69b9..9235970 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -212,5 +212,9 @@ import testing ; [ compile lwm_win32_cs_test.cpp ] [ run local_sp_test.cpp ] + [ run lsp_array_test.cpp ] + [ run lsp_array_n_test.cpp ] + [ run lsp_array_cv_test.cpp ] + [ run lsp_array_cast_test.cpp ] ; } diff --git a/test/lsp_array_cast_test.cpp b/test/lsp_array_cast_test.cpp new file mode 100644 index 0000000..183cddc --- /dev/null +++ b/test/lsp_array_cast_test.cpp @@ -0,0 +1,202 @@ +// +// lsp_array_cast_test.cpp +// +// Copyright 2012, 2017 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 + +struct X +{ +}; + +void static_cast_test() +{ + { + boost::local_shared_ptr pv; + + boost::local_shared_ptr pi = boost::static_pointer_cast( pv ); + BOOST_TEST( pi.get() == 0 ); + + boost::local_shared_ptr pi2 = boost::static_pointer_cast( pv ); + BOOST_TEST( pi2.get() == 0 ); + + boost::local_shared_ptr px = boost::static_pointer_cast( pv ); + BOOST_TEST( px.get() == 0 ); + + boost::local_shared_ptr px2 = boost::static_pointer_cast( pv ); + BOOST_TEST( px2.get() == 0 ); + } + + { + boost::local_shared_ptr pi( new int[2] ); + boost::local_shared_ptr pv( pi ); + + boost::local_shared_ptr pi2 = boost::static_pointer_cast( pv ); + BOOST_TEST(pi.get() == pi2.get()); + BOOST_TEST(!(pi < pi2 || pi2 < pi)); + + boost::local_shared_ptr pi3 = boost::static_pointer_cast( pv ); + BOOST_TEST(pi.get() == pi3.get()); + BOOST_TEST(!(pi < pi3 || pi3 < pi)); + + boost::local_shared_ptr pv2( pi3 ); + + boost::local_shared_ptr pi4 = boost::static_pointer_cast( pv2 ); + BOOST_TEST(pi.get() == pi4.get()); + BOOST_TEST(!(pi < pi4 || pi4 < pi)); + } + + { + boost::local_shared_ptr px( new X[4] ); + boost::local_shared_ptr pv( px ); + + boost::local_shared_ptr px2 = boost::static_pointer_cast( pv ); + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(!(px < px2 || px2 < px)); + + boost::local_shared_ptr px3 = boost::static_pointer_cast( pv ); + BOOST_TEST(px.get() == px3.get()); + BOOST_TEST(!(px < px3 || px3 < px)); + + boost::local_shared_ptr pv2( px3 ); + + boost::local_shared_ptr px4 = boost::static_pointer_cast( pv2 ); + BOOST_TEST(px.get() == px4.get()); + BOOST_TEST(!(px < px4 || px4 < px)); + } +} + +void const_cast_test() +{ + { + boost::local_shared_ptr px; + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST( px2.get() == 0 ); + } + + { + boost::local_shared_ptr px; + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST( px2.get() == 0 ); + } + + { + boost::local_shared_ptr px; + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST( px2.get() == 0 ); + } + + { + boost::local_shared_ptr px; + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST( px2.get() == 0 ); + } + + { + boost::local_shared_ptr px( new int[3] ); + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(!(px < px2 || px2 < px)); + } + + { + boost::local_shared_ptr px( new int[3] ); + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(!(px < px2 || px2 < px)); + } + + { + boost::local_shared_ptr px( new X[4] ); + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(!(px < px2 || px2 < px)); + } + + { + boost::local_shared_ptr px( new X[4] ); + + boost::local_shared_ptr px2 = boost::const_pointer_cast(px); + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(!(px < px2 || px2 < px)); + } +} + +void reinterpret_cast_test() +{ + { + boost::local_shared_ptr pi; + BOOST_TEST( pi.get() == 0 ); + + boost::local_shared_ptr pi2 = boost::reinterpret_pointer_cast( pi ); + BOOST_TEST( pi2.get() == 0 ); + + boost::local_shared_ptr pi3 = boost::reinterpret_pointer_cast( pi2 ); + BOOST_TEST( pi3.get() == 0 ); + } + + { + boost::local_shared_ptr px; + BOOST_TEST( px.get() == 0 ); + + boost::local_shared_ptr px2 = boost::reinterpret_pointer_cast( px ); + BOOST_TEST( px2.get() == 0 ); + + boost::local_shared_ptr px3 = boost::reinterpret_pointer_cast( px2 ); + BOOST_TEST( px3.get() == 0 ); + } + + { + boost::local_shared_ptr pi( new int[2] ); + + boost::local_shared_ptr pi2 = boost::reinterpret_pointer_cast( pi ); + BOOST_TEST(pi.get() == pi2.get()); + BOOST_TEST(!(pi < pi2 || pi2 < pi)); + + boost::local_shared_ptr pi3 = boost::reinterpret_pointer_cast( pi2 ); + BOOST_TEST(pi.get() == pi3.get()); + BOOST_TEST(!(pi < pi3 || pi3 < pi)); + + boost::local_shared_ptr pi4 = boost::reinterpret_pointer_cast( pi3 ); + BOOST_TEST(pi.get() == pi4.get()); + BOOST_TEST(!(pi < pi4 || pi4 < pi)); + } + + { + boost::local_shared_ptr px( new X[4] ); + + boost::local_shared_ptr px2 = boost::reinterpret_pointer_cast( px ); + BOOST_TEST(px.get() == px2.get()); + BOOST_TEST(!(px < px2 || px2 < px)); + + boost::local_shared_ptr px3 = boost::reinterpret_pointer_cast( px2 ); + BOOST_TEST(px.get() == px3.get()); + BOOST_TEST(!(px < px3 || px3 < px)); + + boost::local_shared_ptr px4 = boost::reinterpret_pointer_cast( px3 ); + BOOST_TEST(px.get() == px4.get()); + BOOST_TEST(!(px < px4 || px4 < px)); + } +} + +int main() +{ + static_cast_test(); + const_cast_test(); + reinterpret_cast_test(); + + return boost::report_errors(); +} diff --git a/test/lsp_array_cv_test.cpp b/test/lsp_array_cv_test.cpp new file mode 100644 index 0000000..869d206 --- /dev/null +++ b/test/lsp_array_cv_test.cpp @@ -0,0 +1,60 @@ +// +// lsp_array_cv_test.cpp +// +// Copyright 2012, 2017 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 + +struct X +{ +}; + +class B +{ +}; + +class D: public B +{ +}; + +#define TEST_CONV( T, U ) \ + { \ + boost::local_shared_ptr< T > p1; \ + boost::local_shared_ptr< U > p2( p1 ); \ + p2 = p1; \ + boost::local_shared_ptr< U > p3 = boost::local_shared_ptr< T >(); \ + p3 = boost::local_shared_ptr< T >(); \ + } + +#define TEST_CV_TRUE( T, U ) \ + TEST_CONV( T, U ) \ + TEST_CONV( T, const U ) \ + TEST_CONV( T, volatile U ) \ + TEST_CONV( T, const volatile U ) \ + TEST_CONV( const T, const U ) \ + TEST_CONV( const T, const volatile U ) \ + TEST_CONV( volatile T, volatile U ) \ + TEST_CONV( volatile T, const volatile U ) \ + TEST_CONV( const volatile T, const volatile U ) + +int main() +{ + TEST_CV_TRUE( X, X ) + TEST_CV_TRUE( X, void ) + TEST_CV_TRUE( D, B ) + + TEST_CV_TRUE( X[], X[] ) + TEST_CV_TRUE( X[3], X[3] ) + + TEST_CV_TRUE( X[3], X[] ) + + TEST_CV_TRUE( X[], void ) + TEST_CV_TRUE( X[3], void ) + + return 0; +} diff --git a/test/lsp_array_n_test.cpp b/test/lsp_array_n_test.cpp new file mode 100644 index 0000000..a31e264 --- /dev/null +++ b/test/lsp_array_n_test.cpp @@ -0,0 +1,248 @@ +// +// lsp_array_n_test.cpp +// +// Copyright 2012, 2017 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 +#include + +class X: public boost::enable_shared_from_this< X > +{ +public: + + static int allocations; + static int instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + + void* operator new[]( std::size_t n ) + { + ++allocations; + return ::operator new[]( n ); + } + + void operator delete[]( void* p ) + { + --allocations; + ::operator delete[]( p ); + } + +private: + + X( X const& ); + X& operator=( X const& ); +}; + +int X::allocations = 0; +int X::instances = 0; + +template< class T> class array_deleter +{ +public: + + static int calls; + + void operator()( T * p ) const + { + ++calls; + delete[] p; + } + +private: + + template< class Y > void operator()( Y * p ) const; +}; + +template< class T > int array_deleter< T >::calls = 0; + +int main() +{ + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + + { + boost::local_shared_ptr px; + BOOST_TEST( !px ); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + + boost::local_shared_ptr px2( new X[ 3 ] ); + BOOST_TEST( px2 ); + + try + { + px2[0].shared_from_this(); + BOOST_ERROR( "px2[0].shared_from_this() failed to throw" ); + } + catch( boost::bad_weak_ptr const& ) + { + } + catch( ... ) + { + BOOST_ERROR( "px2[0].shared_from_this() threw something else than bad_weak_ptr" ); + } + + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 3 ); + + { + X & rx = px2[ 0 ]; + BOOST_TEST( &rx == px2.get() ); + } + + boost::local_shared_ptr px3( px2 ); + BOOST_TEST( px3 == px2 ); + BOOST_TEST( !( px2 < px3 ) && !( px3 < px2 ) ); + + { + X const & rx = px3[ 1 ]; + BOOST_TEST( &rx == px3.get() + 1 ); + } + + px3.reset(); + px3 = px2; + BOOST_TEST( px3 == px2 ); + BOOST_TEST( !( px2 < px3 ) && !( px3 < px2 ) ); + + boost::local_shared_ptr px4( px2 ); + BOOST_TEST( px4 == px2 ); + BOOST_TEST( !( px2 < px4 ) && !( px4 < px2 ) ); + + { + X volatile & rx = px4[ 2 ]; + BOOST_TEST( &rx == px4.get() + 2 ); + } + + px4.reset(); + px4 = px2; + BOOST_TEST( px4 == px2 ); + BOOST_TEST( !( px2 < px4 ) && !( px4 < px2 ) ); + + boost::local_shared_ptr px5( px2 ); + BOOST_TEST( px5 == px2 ); + BOOST_TEST( !( px2 < px5 ) && !( px5 < px2 ) ); + + px5.reset(); + px5 = px2; + BOOST_TEST( px5 == px2 ); + BOOST_TEST( !( px2 < px5 ) && !( px5 < px2 ) ); + + boost::weak_ptr wp( px ); + BOOST_TEST( wp.lock() == px ); + + boost::weak_ptr wp2( px2 ); + BOOST_TEST( wp2.lock() == px2 ); + + wp2.reset(); + wp2 = px2; + BOOST_TEST( wp2.lock() == px2 ); + + boost::weak_ptr wp3( px2 ); + BOOST_TEST( wp3.lock() == px2 ); + + wp3.reset(); + wp3 = px2; + BOOST_TEST( wp3.lock() == px2 ); + + boost::weak_ptr wp4( px2 ); + BOOST_TEST( wp4.lock() == px2 ); + + wp4.reset(); + wp4 = px2; + BOOST_TEST( wp4.lock() == px2 ); + + boost::weak_ptr wp5( px2 ); + BOOST_TEST( wp5.lock() == px2 ); + + wp5.reset(); + wp5 = px2; + BOOST_TEST( wp5.lock() == px2 ); + + px2.reset(); + + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 3 ); + + px3.reset(); + px4.reset(); + px5.reset(); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + + BOOST_TEST( wp2.lock() == 0 ); + BOOST_TEST( wp3.lock() == 0 ); + BOOST_TEST( wp4.lock() == 0 ); + BOOST_TEST( wp5.lock() == 0 ); + } + + { + boost::local_shared_ptr px( new X[ 5 ], array_deleter< X >() ); + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 5 ); + + try + { + px[0].shared_from_this(); + BOOST_ERROR( "px[0].shared_from_this() failed to throw" ); + } + catch( boost::bad_weak_ptr const& ) + { + } + catch( ... ) + { + BOOST_ERROR( "px[0].shared_from_this() threw something else than bad_weak_ptr" ); + } + + px.reset(); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( array_deleter< X >::calls == 1 ); + } + + { + boost::local_shared_ptr px( new X[ 6 ], array_deleter< X >(), std::allocator< X >() ); + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 6 ); + + try + { + px[0].shared_from_this(); + BOOST_ERROR( "px[0].shared_from_this() failed to throw" ); + } + catch( boost::bad_weak_ptr const& ) + { + } + catch( ... ) + { + BOOST_ERROR( "px[0].shared_from_this() threw something else than bad_weak_ptr" ); + } + + px.reset(); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( array_deleter< X >::calls == 2 ); + } + + return boost::report_errors(); +} diff --git a/test/lsp_array_test.cpp b/test/lsp_array_test.cpp new file mode 100644 index 0000000..77728ea --- /dev/null +++ b/test/lsp_array_test.cpp @@ -0,0 +1,311 @@ +// +// lsp_array_test.cpp +// +// Copyright 2012, 2017 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 +#include + +class X: public boost::enable_shared_from_this< X > +{ +public: + + static int allocations; + static int instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + + void* operator new[]( std::size_t n ) + { + ++allocations; + return ::operator new[]( n ); + } + + void operator delete[]( void* p ) + { + --allocations; + ::operator delete[]( p ); + } + +private: + + X( X const& ); + X& operator=( X const& ); +}; + +int X::allocations = 0; +int X::instances = 0; + +template< class T> class array_deleter +{ +public: + + static int calls; + + void operator()( T * p ) const + { + ++calls; + delete[] p; + } + +private: + + template< class Y > void operator()( Y * p ) const; +}; + +template< class T > int array_deleter< T >::calls = 0; + +int main() +{ + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + + { + boost::local_shared_ptr px; + BOOST_TEST( !px ); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + + boost::local_shared_ptr px2( new X[ 3 ] ); + BOOST_TEST( px2 ); + + try + { + px2[0].shared_from_this(); + BOOST_ERROR( "px2[0].shared_from_this() failed to throw" ); + } + catch( boost::bad_weak_ptr const& ) + { + } + catch( ... ) + { + BOOST_ERROR( "px2[0].shared_from_this() threw something else than bad_weak_ptr" ); + } + + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 3 ); + + { + X & rx = px2[ 0 ]; + BOOST_TEST( &rx == px2.get() ); + } + + boost::local_shared_ptr px3( px2 ); + BOOST_TEST( px3 == px2 ); + BOOST_TEST( !( px2 < px3 ) && !( px3 < px2 ) ); + + { + X const & rx = px3[ 1 ]; + BOOST_TEST( &rx == px3.get() + 1 ); + } + + px3.reset(); + px3 = px2; + BOOST_TEST( px3 == px2 ); + BOOST_TEST( !( px2 < px3 ) && !( px3 < px2 ) ); + + boost::local_shared_ptr px4( px2 ); + BOOST_TEST( px4 == px2 ); + BOOST_TEST( !( px2 < px4 ) && !( px4 < px2 ) ); + + { + X volatile & rx = px4[ 2 ]; + BOOST_TEST( &rx == px4.get() + 2 ); + } + + px4.reset(); + px4 = px2; + BOOST_TEST( px4 == px2 ); + BOOST_TEST( !( px2 < px4 ) && !( px4 < px2 ) ); + + boost::local_shared_ptr px5( px2 ); + BOOST_TEST( px5 == px2 ); + BOOST_TEST( !( px2 < px5 ) && !( px5 < px2 ) ); + + px5.reset(); + px5 = px2; + BOOST_TEST( px5 == px2 ); + BOOST_TEST( !( px2 < px5 ) && !( px5 < px2 ) ); + + boost::weak_ptr wp( px ); + BOOST_TEST( wp.lock() == px ); + + boost::weak_ptr wp2( px2 ); + BOOST_TEST( wp2.lock() == px2 ); + + wp2.reset(); + wp2 = px2; + BOOST_TEST( wp2.lock() == px2 ); + + boost::weak_ptr wp3( px2 ); + BOOST_TEST( wp3.lock() == px2 ); + + wp3.reset(); + wp3 = px2; + BOOST_TEST( wp3.lock() == px2 ); + + boost::weak_ptr wp4( px2 ); + BOOST_TEST( wp4.lock() == px2 ); + + wp4.reset(); + wp4 = px2; + BOOST_TEST( wp4.lock() == px2 ); + + boost::weak_ptr wp5( px2 ); + BOOST_TEST( wp5.lock() == px2 ); + + wp5.reset(); + wp5 = px2; + BOOST_TEST( wp5.lock() == px2 ); + + px2.reset(); + + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 3 ); + + px3.reset(); + px4.reset(); + px5.reset(); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + + BOOST_TEST( wp2.lock() == 0 ); + BOOST_TEST( wp3.lock() == 0 ); + BOOST_TEST( wp4.lock() == 0 ); + BOOST_TEST( wp5.lock() == 0 ); + } + +#if !defined( BOOST_NO_CXX11_SMART_PTR ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + { + std::unique_ptr px( new X[ 4 ] ); + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 4 ); + + boost::local_shared_ptr px2( std::move( px ) ); + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 4 ); + BOOST_TEST( px.get() == 0 ); + + try + { + px2[0].shared_from_this(); + BOOST_ERROR( "px2[0].shared_from_this() failed to throw" ); + } + catch( boost::bad_weak_ptr const& ) + { + } + catch( ... ) + { + BOOST_ERROR( "px2[0].shared_from_this() threw something else than bad_weak_ptr" ); + } + + px2.reset(); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + } + + { + std::unique_ptr px( new X[ 4 ] ); + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 4 ); + + boost::local_shared_ptr px2; + px2 = std::move( px ); + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 4 ); + BOOST_TEST( px.get() == 0 ); + + try + { + px2[0].shared_from_this(); + BOOST_ERROR( "px2[0].shared_from_this() failed to throw" ); + } + catch( boost::bad_weak_ptr const& ) + { + } + catch( ... ) + { + BOOST_ERROR( "px2[0].shared_from_this() threw something else than bad_weak_ptr" ); + } + + px2.reset(); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + } + +#endif + + { + boost::local_shared_ptr px( new X[ 5 ], array_deleter< X >() ); + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 5 ); + + try + { + px[0].shared_from_this(); + BOOST_ERROR( "px[0].shared_from_this() failed to throw" ); + } + catch( boost::bad_weak_ptr const& ) + { + } + catch( ... ) + { + BOOST_ERROR( "px[0].shared_from_this() threw something else than bad_weak_ptr" ); + } + + px.reset(); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( array_deleter< X >::calls == 1 ); + } + + { + boost::local_shared_ptr px( new X[ 6 ], array_deleter< X >(), std::allocator< X >() ); + BOOST_TEST( X::allocations == 1 ); + BOOST_TEST( X::instances == 6 ); + + try + { + px[0].shared_from_this(); + BOOST_ERROR( "px[0].shared_from_this() failed to throw" ); + } + catch( boost::bad_weak_ptr const& ) + { + } + catch( ... ) + { + BOOST_ERROR( "px[0].shared_from_this() threw something else than bad_weak_ptr" ); + } + + px.reset(); + + BOOST_TEST( X::allocations == 0 ); + BOOST_TEST( X::instances == 0 ); + BOOST_TEST( array_deleter< X >::calls == 2 ); + } + + return boost::report_errors(); +}