diff --git a/include/boost/smart_ptr/detail/shared_count.hpp b/include/boost/smart_ptr/detail/shared_count.hpp index 1e7d688..cd07ed6 100644 --- a/include/boost/smart_ptr/detail/shared_count.hpp +++ b/include/boost/smart_ptr/detail/shared_count.hpp @@ -40,13 +40,18 @@ # include // std::bad_alloc #endif -#if !defined( BOOST_NO_CXX11_SMART_PTR ) -# include -#endif +#include namespace boost { +namespace movelib +{ + + template< class T, class D > class unique_ptr; + +} // namespace movelib + namespace detail { @@ -63,8 +68,6 @@ template< class D > struct sp_inplace_tag { }; -#if !defined( BOOST_NO_CXX11_SMART_PTR ) - template< class T > class sp_reference_wrapper { public: @@ -93,8 +96,6 @@ template< class D > struct sp_convert_reference< D& > typedef sp_reference_wrapper< D > type; }; -#endif - class weak_count; class shared_count @@ -438,6 +439,29 @@ public: #endif + template + explicit shared_count( boost::movelib::unique_ptr & r ): pi_( 0 ) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { + typedef typename sp_convert_reference::type D2; + + D2 d2( r.get_deleter() ); + pi_ = new sp_counted_impl_pd< typename boost::movelib::unique_ptr::pointer, D2 >( r.get(), d2 ); + +#ifdef BOOST_NO_EXCEPTIONS + + if( pi_ == 0 ) + { + boost::throw_exception( std::bad_alloc() ); + } + +#endif + + r.release(); + } + ~shared_count() // nothrow { if( pi_ != 0 ) pi_->release(); diff --git a/include/boost/smart_ptr/shared_ptr.hpp b/include/boost/smart_ptr/shared_ptr.hpp index 8be92ab..991ca3d 100644 --- a/include/boost/smart_ptr/shared_ptr.hpp +++ b/include/boost/smart_ptr/shared_ptr.hpp @@ -55,6 +55,13 @@ template class weak_ptr; template class enable_shared_from_this; class enable_shared_from_raw; +namespace movelib +{ + + template< class T, class D > class unique_ptr; + +} // namespace movelib + namespace detail { @@ -495,6 +502,17 @@ public: #endif + template< class Y, class D > + shared_ptr( boost::movelib::unique_ptr< Y, D > r ): px( r.get() ), pn() + { + boost::detail::sp_assert_convertible< Y, T >(); + + typename boost::movelib::unique_ptr< Y, D >::pointer tmp = r.get(); + pn = boost::detail::shared_count( r ); + + boost::detail::sp_deleter_construct( this, tmp ); + } + // assignment shared_ptr & operator=( shared_ptr const & r ) BOOST_NOEXCEPT @@ -556,6 +574,27 @@ public: #endif + template + shared_ptr & operator=( boost::movelib::unique_ptr r ) + { + // this_type( static_cast< unique_ptr && >( r ) ).swap( *this ); + + boost::detail::sp_assert_convertible< Y, T >(); + + typename boost::movelib::unique_ptr< Y, D >::pointer p = r.get(); + + shared_ptr tmp; + + tmp.px = p; + tmp.pn = boost::detail::shared_count( r ); + + boost::detail::sp_deleter_construct( &tmp, p ); + + tmp.swap( *this ); + + return *this; + } + // Move support #if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index b17e55f..62fab50 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -179,5 +179,7 @@ import testing ; [ run weak_from_this_test.cpp ] [ run weak_from_this_test2.cpp ] + + [ run sp_bml_unique_ptr_test.cpp ] ; } diff --git a/test/sp_bml_unique_ptr_test.cpp b/test/sp_bml_unique_ptr_test.cpp new file mode 100644 index 0000000..0d4921d --- /dev/null +++ b/test/sp_bml_unique_ptr_test.cpp @@ -0,0 +1,239 @@ +// +// sp_bml_unique_ptr_test.cpp +// +// Copyright (c) 2012, 2015 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 + +struct X: public boost::enable_shared_from_this< X > +{ + static int instances; + + X() + { + ++instances; + } + + ~X() + { + --instances; + } + +private: + + X( X const & ); + X & operator=( X const & ); +}; + +int X::instances = 0; + +struct Y +{ + static int instances; + + bool deleted_; + + Y(): deleted_( false ) + { + ++instances; + } + + ~Y() + { + BOOST_TEST( deleted_ ); + --instances; + } + +private: + + Y( Y const & ); + Y & operator=( Y const & ); +}; + +int Y::instances = 0; + +struct YD +{ + void operator()( Y* p ) const + { + p->deleted_ = true; + delete p; + } +}; + +int main() +{ + { + BOOST_TEST( X::instances == 0 ); + + boost::movelib::unique_ptr p( new X ); + BOOST_TEST( X::instances == 1 ); + + boost::shared_ptr p2( boost::move( p ) ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p.get() == 0 ); + + boost::shared_ptr p3 = p2->shared_from_this(); + BOOST_TEST( p2 == p3 ); + BOOST_TEST( !(p2 < p3) && !(p3 < p2) ); + + p2.reset(); + p3.reset(); + BOOST_TEST( X::instances == 0 ); + + p2 = boost::movelib::unique_ptr( new X ); + BOOST_TEST( X::instances == 1 ); + + p2 = boost::movelib::unique_ptr( new X ); + BOOST_TEST( X::instances == 1 ); + + p3 = p2->shared_from_this(); + BOOST_TEST( p2 == p3 ); + BOOST_TEST( !(p2 < p3) && !(p3 < p2) ); + + p2.reset(); + p3.reset(); + BOOST_TEST( X::instances == 0 ); + } + + { + BOOST_TEST( X::instances == 0 ); + + boost::movelib::unique_ptr p( new X ); + BOOST_TEST( X::instances == 1 ); + + boost::shared_ptr p2( boost::move( p ) ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p.get() == 0 ); + + boost::shared_ptr p3 = p2->shared_from_this(); + BOOST_TEST( p2 == p3 ); + BOOST_TEST( !(p2 < p3) && !(p3 < p2) ); + + p2.reset(); + p3.reset(); + BOOST_TEST( X::instances == 0 ); + + p2 = boost::movelib::unique_ptr( new X ); + BOOST_TEST( X::instances == 1 ); + + p2 = boost::movelib::unique_ptr( new X ); + BOOST_TEST( X::instances == 1 ); + + p3 = p2->shared_from_this(); + BOOST_TEST( p2 == p3 ); + BOOST_TEST( !(p2 < p3) && !(p3 < p2) ); + + p2.reset(); + p3.reset(); + BOOST_TEST( X::instances == 0 ); + } + + { + BOOST_TEST( X::instances == 0 ); + + boost::movelib::unique_ptr p( new X ); + BOOST_TEST( X::instances == 1 ); + + boost::shared_ptr p2( boost::move( p ) ); + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( p.get() == 0 ); + + p2.reset(); + BOOST_TEST( X::instances == 0 ); + + p2 = boost::movelib::unique_ptr( new X ); + BOOST_TEST( X::instances == 1 ); + + p2 = boost::movelib::unique_ptr( new X ); + BOOST_TEST( X::instances == 1 ); + + p2.reset(); + BOOST_TEST( X::instances == 0 ); + } + + { + BOOST_TEST( Y::instances == 0 ); + + boost::movelib::unique_ptr p( new Y, YD() ); + BOOST_TEST( Y::instances == 1 ); + + boost::shared_ptr p2( boost::move( p ) ); + BOOST_TEST( Y::instances == 1 ); + BOOST_TEST( p.get() == 0 ); + + p2.reset(); + BOOST_TEST( Y::instances == 0 ); + + p2 = boost::movelib::unique_ptr( new Y, YD() ); + BOOST_TEST( Y::instances == 1 ); + + p2 = boost::movelib::unique_ptr( new Y, YD() ); + BOOST_TEST( Y::instances == 1 ); + + p2.reset(); + BOOST_TEST( Y::instances == 0 ); + } + + { + BOOST_TEST( Y::instances == 0 ); + + YD yd; + + boost::movelib::unique_ptr p( new Y, yd ); + BOOST_TEST( Y::instances == 1 ); + + boost::shared_ptr p2( boost::move( p ) ); + BOOST_TEST( Y::instances == 1 ); + BOOST_TEST( p.get() == 0 ); + + p2.reset(); + BOOST_TEST( Y::instances == 0 ); + + p2 = boost::movelib::unique_ptr( new Y, yd ); + BOOST_TEST( Y::instances == 1 ); + + p2 = boost::movelib::unique_ptr( new Y, yd ); + BOOST_TEST( Y::instances == 1 ); + + p2.reset(); + BOOST_TEST( Y::instances == 0 ); + } + + { + BOOST_TEST( Y::instances == 0 ); + + YD yd; + + boost::movelib::unique_ptr p( new Y, yd ); + BOOST_TEST( Y::instances == 1 ); + + boost::shared_ptr p2( boost::move( p ) ); + BOOST_TEST( Y::instances == 1 ); + BOOST_TEST( p.get() == 0 ); + + p2.reset(); + BOOST_TEST( Y::instances == 0 ); + + p2 = boost::movelib::unique_ptr( new Y, yd ); + BOOST_TEST( Y::instances == 1 ); + + p2 = boost::movelib::unique_ptr( new Y, yd ); + BOOST_TEST( Y::instances == 1 ); + + p2.reset(); + BOOST_TEST( Y::instances == 0 ); + } + + return boost::report_errors(); +}