diff --git a/include/boost/smart_ptr/detail/sp_nullptr_t.hpp b/include/boost/smart_ptr/detail/sp_nullptr_t.hpp index ccbb123..219ae80 100644 --- a/include/boost/smart_ptr/detail/sp_nullptr_t.hpp +++ b/include/boost/smart_ptr/detail/sp_nullptr_t.hpp @@ -26,7 +26,7 @@ namespace boost namespace detail { -#if defined( __clang__ ) && !defined( _LIBCPP_VERSION ) && !defined( BOOST_NO_CXX11_DECLTYPE ) +#if !defined( BOOST_NO_CXX11_DECLTYPE ) && ( ( defined( __clang__ ) && !defined( _LIBCPP_VERSION ) ) || defined( __INTEL_COMPILER ) ) typedef decltype(nullptr) sp_nullptr_t; diff --git a/include/boost/smart_ptr/enable_shared_from_raw.hpp b/include/boost/smart_ptr/enable_shared_from_raw.hpp index f659c04..1911c07 100644 --- a/include/boost/smart_ptr/enable_shared_from_raw.hpp +++ b/include/boost/smart_ptr/enable_shared_from_raw.hpp @@ -4,7 +4,7 @@ // // enable_shared_from_raw.hpp // -// Copyright 2002, 2009 Peter Dimov +// Copyright 2002, 2009, 2014 Peter Dimov // Copyright 2008-2009 Frank Mori Hess // // Distributed under the Boost Software License, Version 1.0. @@ -72,16 +72,15 @@ private: template< class X, class Y > friend inline void detail::sp_enable_shared_from_this( boost::shared_ptr * ppx, Y const * py, boost::enable_shared_from_raw const * pe ); #endif - shared_ptr shared_from_this() + shared_ptr shared_from_this() const { init_weak_once(); - return shared_ptr( weak_this_ ); + return shared_ptr( weak_this_ ); } - shared_ptr shared_from_this() const + shared_ptr shared_from_this() const volatile { - init_weak_once(); - return shared_ptr( weak_this_ ); + return const_cast< enable_shared_from_raw const * >( this )->shared_from_this(); } // Note: invoked automatically by shared_ptr; do not call @@ -107,9 +106,11 @@ private: } } - mutable weak_ptr weak_this_; + mutable weak_ptr weak_this_; + private: - mutable shared_ptr shared_this_; + + mutable shared_ptr shared_this_; }; template diff --git a/include/boost/smart_ptr/shared_ptr.hpp b/include/boost/smart_ptr/shared_ptr.hpp index 83b0451..82ece8b 100644 --- a/include/boost/smart_ptr/shared_ptr.hpp +++ b/include/boost/smart_ptr/shared_ptr.hpp @@ -893,7 +893,7 @@ class esft2_deleter_wrapper { private: - shared_ptr deleter_; + shared_ptr deleter_; public: diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 19520c2..0d52b93 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -60,8 +60,6 @@ import testing ; [ run sp_recursive_assign2_test.cpp ] [ run sp_recursive_assign_rv_test.cpp ] [ run sp_recursive_assign2_rv_test.cpp ] - [ run esft_constructor_test.cpp ] - [ run enable_shared_from_raw_test.cpp ] [ compile-fail auto_ptr_lv_fail.cpp ] [ run atomic_count_test2.cpp ] [ run sp_typeinfo_test.cpp ] @@ -163,5 +161,12 @@ 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 ] + [ run shared_from_raw_test5.cpp ] + [ run weak_from_raw_test.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(); +} diff --git a/test/esft_constructor_test.cpp b/test/shared_from_raw_test5.cpp similarity index 94% rename from test/esft_constructor_test.cpp rename to test/shared_from_raw_test5.cpp index 32a25b5..fcf4e81 100644 --- a/test/esft_constructor_test.cpp +++ b/test/shared_from_raw_test5.cpp @@ -1,9 +1,9 @@ // -// esft_constructor_test.cpp +// shared_from_raw_test5.cpp - was 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). +// A test for calling shared_from_raw 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 @@ -13,6 +13,7 @@ // See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // + #include #include #include diff --git a/test/sp_nullptr_test.cpp b/test/sp_nullptr_test.cpp index a1779bb..1b3965c 100644 --- a/test/sp_nullptr_test.cpp +++ b/test/sp_nullptr_test.cpp @@ -9,6 +9,7 @@ // #include +#include #include #include #include @@ -37,7 +38,7 @@ private: int X::instances = 0; -void f( std::nullptr_t ) +void f( boost::detail::sp_nullptr_t ) { } diff --git a/test/enable_shared_from_raw_test.cpp b/test/weak_from_raw_test.cpp similarity index 100% rename from test/enable_shared_from_raw_test.cpp rename to test/weak_from_raw_test.cpp