diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 19520c2..1fe4078 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -163,5 +163,10 @@ import testing ; [ run make_unique_array_test.cpp ] [ run make_unique_array_noinit_test.cpp ] [ run make_unique_array_throws_test.cpp ] + + [ run shared_from_raw_test.cpp ] + [ run shared_from_raw_test2.cpp ] + [ run shared_from_raw_test3.cpp ] + [ run shared_from_raw_test4.cpp ] ; } diff --git a/test/shared_from_raw_test.cpp b/test/shared_from_raw_test.cpp new file mode 100644 index 0000000..cf5500f --- /dev/null +++ b/test/shared_from_raw_test.cpp @@ -0,0 +1,170 @@ +// +// shared_from_raw_test - based on shared_from_this_test +// +// Copyright (c) 2002, 2003, 2014 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: + + virtual void f() = 0; + +protected: + + ~X() {} +}; + +class Y +{ +public: + + virtual boost::shared_ptr getX() = 0; + +protected: + + ~Y() {} +}; + +boost::shared_ptr createY(); + +void test() +{ + boost::shared_ptr py = createY(); + BOOST_TEST(py.get() != 0); + BOOST_TEST(py.use_count() == 1); + + try + { + boost::shared_ptr px = py->getX(); + BOOST_TEST(px.get() != 0); + BOOST_TEST(py.use_count() == 2); + + px->f(); + +#if !defined( BOOST_NO_RTTI ) + 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); +#endif + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "py->getX() failed" ); + } +} + +void test2(); +void test3(); + +int main() +{ + test(); + test2(); + test3(); + return boost::report_errors(); +} + +// virtual inheritance to stress the implementation +// (prevents Y* -> impl*, enable_shared_from_raw* -> impl* casts) + +class impl: public X, public virtual Y, public virtual boost::enable_shared_from_raw +{ +public: + + virtual void f() + { + } + + virtual boost::shared_ptr getX() + { + boost::shared_ptr pi = boost::shared_from_raw( this ); + BOOST_TEST( pi.get() == this ); + return pi; + } +}; + +// intermediate impl2 to stress the implementation + +class impl2: public impl +{ +}; + +boost::shared_ptr createY() +{ + boost::shared_ptr pi(new impl2); + return pi; +} + +void test2() +{ + boost::shared_ptr pi(static_cast(0)); +} + +// + +struct V: public boost::enable_shared_from_raw +{ +}; + +void test3() +{ + boost::shared_ptr p( new V ); + + try + { + boost::shared_ptr q = boost::shared_from_raw( p.get() ); + BOOST_TEST( p == q ); + BOOST_TEST( !(p < q) && !(q < p) ); + } + catch( boost::bad_weak_ptr const & ) + { + BOOST_ERROR( "shared_from_this( p.get() ) failed" ); + } + + V v2( *p ); + + try + { + // shared_from_raw differs from shared_from_this; + // it will not throw here and will create a shared_ptr + + boost::shared_ptr r = boost::shared_from_raw( &v2 ); + + // check if the shared_ptr is correct and that it does + // not share ownership with p + + BOOST_TEST( r.get() == &v2 ); + BOOST_TEST( p != r ); + BOOST_TEST( (p < r) || (r < p) ); + } + catch( boost::bad_weak_ptr const & ) + { + BOOST_ERROR("shared_from_raw( &v2 ) failed"); + } + + try + { + *p = V(); + boost::shared_ptr r = boost::shared_from_raw( p.get() ); + BOOST_TEST( p == r ); + BOOST_TEST( !(p < r) && !(r < p) ); + } + catch( boost::bad_weak_ptr const & ) + { + BOOST_ERROR("shared_from_raw( p.get() ) threw bad_weak_ptr after *p = V()"); + } +} diff --git a/test/shared_from_raw_test2.cpp b/test/shared_from_raw_test2.cpp new file mode 100644 index 0000000..8148a6b --- /dev/null +++ b/test/shared_from_raw_test2.cpp @@ -0,0 +1,219 @@ +// +// shared_from_raw_test2.cpp - based on esft_regtest.cpp +// +// Copyright (c) 2008, 2014 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_raw +{ +private: + + int destroyed_; + int deleted_; + int expected_; + +private: + + X( X const& ); + X& operator=( X const& ); + +public: + + static int instances; + +public: + + explicit X( int expected ): destroyed_( 0 ), deleted_( 0 ), expected_( expected ) + { + ++instances; + } + + ~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; + +void test() +{ + BOOST_TEST( X::instances == 0 ); + + { + X x( 0 ); + BOOST_TEST( X::instances == 1 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + std::auto_ptr px( new X( 0 ) ); + BOOST_TEST( X::instances == 1 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr px( new X( 0 ) ); + BOOST_TEST( X::instances == 1 ); + + boost::weak_ptr wp( px ); + BOOST_TEST( !wp.expired() ); + + px.reset(); + + BOOST_TEST( wp.expired() ); + } + + BOOST_TEST( X::instances == 0 ); + + { + X x( 1 ); + boost::shared_ptr px( &x, X::deleter ); + BOOST_TEST( X::instances == 1 ); + + X::deleter_type * pd = boost::get_deleter( px ); + BOOST_TEST( pd != 0 && *pd == X::deleter ); + + boost::weak_ptr wp( px ); + BOOST_TEST( !wp.expired() ); + + px.reset(); + + BOOST_TEST( wp.expired() ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr px( new X( 1 ), X::deleter2 ); + BOOST_TEST( X::instances == 1 ); + + X::deleter_type * pd = boost::get_deleter( px ); + BOOST_TEST( pd != 0 && *pd == X::deleter2 ); + + boost::weak_ptr wp( px ); + BOOST_TEST( !wp.expired() ); + + px.reset(); + + BOOST_TEST( wp.expired() ); + } + + BOOST_TEST( X::instances == 0 ); +} + +struct V: public boost::enable_shared_from_raw +{ + virtual ~V() {} + std::string m_; +}; + +struct V2 +{ + virtual ~V2() {} + std::string m2_; +}; + +struct W: V2, V +{ +}; + +void test2() +{ + boost::shared_ptr p( new W ); +} + +void test3() +{ + V * p = new W; + boost::shared_ptr pv( p ); + BOOST_TEST( pv.get() == p ); + BOOST_TEST( pv.use_count() == 1 ); +} + +struct null_deleter +{ + void operator()( void const* ) const {} +}; + +void test4() +{ + boost::shared_ptr pv( new V ); + boost::shared_ptr pv2( pv.get(), null_deleter() ); + BOOST_TEST( pv2.get() == pv.get() ); + BOOST_TEST( pv2.use_count() == 1 ); +} + +void test5() +{ + V v; + + boost::shared_ptr p1( &v, null_deleter() ); + BOOST_TEST( p1.get() == &v ); + BOOST_TEST( p1.use_count() == 1 ); + + try + { + boost::shared_from_raw( p1.get() ); + } + catch( ... ) + { + BOOST_ERROR( "shared_from_raw( p1.get() ) failed" ); + } + + p1.reset(); + + boost::shared_ptr p2( &v, null_deleter() ); + BOOST_TEST( p2.get() == &v ); + BOOST_TEST( p2.use_count() == 1 ); + + try + { + boost::shared_from_raw( p2.get() ); + } + catch( ... ) + { + BOOST_ERROR( "shared_from_raw( p2.get() ) failed" ); + } +} + +int main() +{ + test(); + test2(); + test3(); + test4(); + test5(); + + return boost::report_errors(); +} diff --git a/test/shared_from_raw_test3.cpp b/test/shared_from_raw_test3.cpp new file mode 100644 index 0000000..8c3adaf --- /dev/null +++ b/test/shared_from_raw_test3.cpp @@ -0,0 +1,52 @@ +// +// shared_from_raw_test3 - based on esft_second_ptr_test.cpp +// +// This test has been extracted from a real +// scenario that occurs in Boost.Python +// +// Copyright 2009, 2014 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_raw +{ +}; + +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 = boost::shared_from_raw( px.get() ); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "shared_from_raw( px.get() ) failed" ); + } + + return boost::report_errors(); +} diff --git a/test/shared_from_raw_test4.cpp b/test/shared_from_raw_test4.cpp new file mode 100644 index 0000000..ab0658e --- /dev/null +++ b/test/shared_from_raw_test4.cpp @@ -0,0 +1,56 @@ +// +// shared_from_raw_test4 - based on esft_void_test.cpp +// +// Copyright 2009, 2014 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_raw +{ +}; + +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 = boost::shared_from_raw( px.get() ); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "shared_from_this( px.get() ) failed" ); + } + + boost::shared_ptr< X const volatile > px2( px ); + + try + { + boost::shared_ptr< X const volatile > qx2 = boost::shared_from_raw( px2.get() ); + + BOOST_TEST( px2 == qx2 ); + BOOST_TEST( !( px2 < qx2 ) && !( qx2 < px2 ) ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "shared_from_this( px2.get() ) failed" ); + } + + return boost::report_errors(); +}