diff --git a/include/boost/smart_ptr/detail/shared_count.hpp b/include/boost/smart_ptr/detail/shared_count.hpp index f96a220..2c99f02 100644 --- a/include/boost/smart_ptr/detail/shared_count.hpp +++ b/include/boost/smart_ptr/detail/shared_count.hpp @@ -37,6 +37,10 @@ #include // std::less #include // std::bad_alloc +#if !defined( BOOST_NO_CXX11_SMART_PTR ) +# include +#endif + namespace boost { @@ -56,6 +60,38 @@ template< class D > struct sp_inplace_tag { }; +#if !defined( BOOST_NO_CXX11_SMART_PTR ) + +template< class T > class sp_reference_wrapper +{ +public: + + explicit sp_reference_wrapper( T & t): t_( boost::addressof( t ) ) + { + } + + template< class Y > void operator()( Y * p ) const + { + (*t_)( p ); + } + +private: + + T * t_; +}; + +template< class D > struct sp_convert_reference +{ + typedef D type; +}; + +template< class D > struct sp_convert_reference< D& > +{ + typedef sp_reference_wrapper< D > type; +}; + +#endif + class weak_count; class shared_count @@ -300,6 +336,33 @@ public: #endif +#if !defined( BOOST_NO_CXX11_SMART_PTR ) + + template + explicit shared_count( std::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< Y*, D2 >( r.get(), d2 ); + +#ifdef BOOST_NO_EXCEPTIONS + + if( pi_ == 0 ) + { + boost::throw_exception( std::bad_alloc() ); + } + +#endif + + r.release(); + } + +#endif + ~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 0932cc3..924f621 100644 --- a/include/boost/smart_ptr/shared_ptr.hpp +++ b/include/boost/smart_ptr/shared_ptr.hpp @@ -298,6 +298,18 @@ public: #endif // BOOST_NO_AUTO_PTR +#if !defined( BOOST_NO_CXX11_SMART_PTR ) + + template< class Y, class D > + shared_ptr( std::unique_ptr< Y, D > && r): px( r.get() ), pn() + { + Y * tmp = r.get(); + pn = boost::detail::shared_count( r ); + boost::detail::sp_enable_shared_from_this( this, tmp, tmp ); + } + +#endif + // assignment shared_ptr & operator=( shared_ptr const & r ) // never throws diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 66d8007..1df2a3e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -69,5 +69,6 @@ import testing ; [ run get_deleter_array_test.cpp ] [ run ip_hash_test.cpp ] [ run owner_less_test.cpp ] + [ run sp_unique_ptr_test.cpp ] ; } diff --git a/test/sp_unique_ptr_test.cpp b/test/sp_unique_ptr_test.cpp new file mode 100644 index 0000000..70c5aff --- /dev/null +++ b/test/sp_unique_ptr_test.cpp @@ -0,0 +1,152 @@ +// +// sp_unique_ptr_test.cpp +// +// Copyright (c) 2012 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 + +#if !defined( BOOST_NO_CXX11_SMART_PTR ) + +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 ); + + std::unique_ptr p( new X ); + BOOST_TEST( X::instances == 1 ); + + boost::shared_ptr p2( std::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 ); + } + + { + BOOST_TEST( Y::instances == 0 ); + + std::unique_ptr p( new Y, YD() ); + BOOST_TEST( Y::instances == 1 ); + + boost::shared_ptr p2( std::move( p ) ); + BOOST_TEST( Y::instances == 1 ); + BOOST_TEST( p.get() == 0 ); + + p2.reset(); + BOOST_TEST( Y::instances == 0 ); + } + + { + BOOST_TEST( Y::instances == 0 ); + + YD yd; + + std::unique_ptr p( new Y, yd ); + BOOST_TEST( Y::instances == 1 ); + + boost::shared_ptr p2( std::move( p ) ); + BOOST_TEST( Y::instances == 1 ); + BOOST_TEST( p.get() == 0 ); + + p2.reset(); + BOOST_TEST( Y::instances == 0 ); + } + + { + BOOST_TEST( Y::instances == 0 ); + + YD yd; + + std::unique_ptr p( new Y, yd ); + BOOST_TEST( Y::instances == 1 ); + + boost::shared_ptr p2( std::move( p ) ); + BOOST_TEST( Y::instances == 1 ); + BOOST_TEST( p.get() == 0 ); + + p2.reset(); + BOOST_TEST( Y::instances == 0 ); + } + + return boost::report_errors(); +} + +#else // !defined( BOOST_NO_CXX11_SMART_PTR ) + +int main() +{ + return 0; +} + +#endif