diff --git a/include/boost/smart_ptr/detail/sp_counted_impl.hpp b/include/boost/smart_ptr/detail/sp_counted_impl.hpp index 404f982..8702532 100644 --- a/include/boost/smart_ptr/detail/sp_counted_impl.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_impl.hpp @@ -213,7 +213,7 @@ public: { } - sp_counted_impl_pda( P p, A a ): p_( p ), d_(), a_( a ) + sp_counted_impl_pda( P p, A a ): p_( p ), d_( a ), a_( a ) { } diff --git a/include/boost/smart_ptr/make_shared_object.hpp b/include/boost/smart_ptr/make_shared_object.hpp index b0064ad..62372fa 100644 --- a/include/boost/smart_ptr/make_shared_object.hpp +++ b/include/boost/smart_ptr/make_shared_object.hpp @@ -72,6 +72,10 @@ public: { } + template explicit sp_ms_deleter( A const & ) BOOST_NOEXCEPT : initialized_( false ) + { + } + // optimization: do not copy storage_ sp_ms_deleter( sp_ms_deleter const & ) BOOST_NOEXCEPT : initialized_( false ) { @@ -102,6 +106,74 @@ public: } }; +template< class T, class A > class sp_as_deleter +{ +private: + + typedef typename sp_aligned_storage< sizeof( T ), ::boost::alignment_of< T >::value >::type storage_type; + + storage_type storage_; + A a_; + bool initialized_; + +private: + + void destroy() + { + if( initialized_ ) + { + T * p = reinterpret_cast< T* >( storage_.data_ ); + +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + std::allocator_traits::destroy( a_, p ); + +#else + + p->~T(); + +#endif + + initialized_ = false; + } + } + +public: + + sp_as_deleter( A const & a ) BOOST_NOEXCEPT : a_( a ), initialized_( false ) + { + } + + // optimization: do not copy storage_ + sp_as_deleter( sp_as_deleter const & r ) BOOST_NOEXCEPT : a_( r.a_), initialized_( false ) + { + } + + ~sp_as_deleter() + { + destroy(); + } + + void operator()( T * ) + { + destroy(); + } + + static void operator_fn( T* ) // operator() can't be static + { + } + + void * address() BOOST_NOEXCEPT + { + return storage_.data_; + } + + void set_initialized() BOOST_NOEXCEPT + { + initialized_ = true; + } +}; + template< class T > struct sp_if_not_array { typedef boost::shared_ptr< T > type; @@ -190,13 +262,36 @@ template< class T, class... Args > typename boost::detail::sp_if_not_array< T >: template< class T, class A, class... Args > typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, Args && ... args ) { - boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a ); +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) - boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + typedef typename std::allocator_traits::template rebind_alloc A2; + A2 a2( a ); + typedef boost::detail::sp_as_deleter< T, A2 > D; + + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), boost::detail::sp_inplace_tag(), a2 ); + +#else + + typedef boost::detail::sp_ms_deleter< T > D; + + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), boost::detail::sp_inplace_tag(), a ); + +#endif + + D * pd = static_cast< D* >( pt._internal_get_untyped_deleter() ); void * pv = pd->address(); +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + std::allocator_traits::construct( a2, static_cast< T* >( pv ), boost::detail::sp_forward( args )... ); + +#else + ::new( pv ) T( boost::detail::sp_forward( args )... ); + +#endif + pd->set_initialized(); T * pt2 = static_cast< T* >( pv ); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 862d846..fc95688 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -82,6 +82,7 @@ import testing ; [ run shared_ptr_alloc3_test.cpp ] [ run shared_ptr_alloc11_test.cpp ] [ run allocate_shared_alloc11_test.cpp ] + [ run allocate_shared_construct11_test.cpp ] [ compile-fail array_fail_spa_sp_c.cpp ] [ compile-fail array_fail_sp_spa_c.cpp ] diff --git a/test/allocate_shared_construct11_test.cpp b/test/allocate_shared_construct11_test.cpp new file mode 100644 index 0000000..131b4cb --- /dev/null +++ b/test/allocate_shared_construct11_test.cpp @@ -0,0 +1,240 @@ +// allocate_shared_construct11_test.cpp +// +// Test whether allocate_shared uses construct/destroy in C++11 +// +// Copyright 2007-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 +#include +#include + +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + +template< class T > class cxx11_allocator +{ +public: + + typedef T value_type; + + cxx11_allocator() + { + } + + template< class Y > cxx11_allocator( cxx11_allocator const & ) + { + } + + T * allocate( std::size_t n ) + { + return static_cast< T* >( ::operator new( n * sizeof( T ) ) ); + } + + void deallocate( T * p, std::size_t n ) + { + ::operator delete( p ); + } + + template void construct( T * p, Args&&... args ) + { + ::new( static_cast< void* >( p ) ) T( std::forward( args )... ); + } + + void destroy( T * p ) + { + p->~T(); + } +}; + +class X +{ +private: + + X( X const & ); + X & operator=( X const & ); + + void * operator new( std::size_t n ) + { + BOOST_ERROR( "private X::new called" ); + return ::operator new( n ); + } + + void operator delete( void * p ) + { + BOOST_ERROR( "private X::delete called" ); + ::operator delete( p ); + } + +public: + + static int instances; + + int v; + +protected: + + explicit X( int a1 = 0, int a2 = 0, int a3 = 0, int a4 = 0, int a5 = 0, int a6 = 0, int a7 = 0, int a8 = 0, int a9 = 0 ): v( a1+a2+a3+a4+a5+a6+a7+a8+a9 ) + { + ++instances; + } + + ~X() + { + --instances; + } + + friend class cxx11_allocator; +}; + +int X::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( cxx11_allocator() ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 0 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( cxx11_allocator(), 1 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( cxx11_allocator(), 1, 2 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( cxx11_allocator(), 1, 2, 3 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( cxx11_allocator(), 1, 2, 3, 4 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( cxx11_allocator(), 1, 2, 3, 4, 5 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( cxx11_allocator(), 1, 2, 3, 4, 5, 6 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( cxx11_allocator(), 1, 2, 3, 4, 5, 6, 7 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6+7 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( cxx11_allocator(), 1, 2, 3, 4, 5, 6, 7, 8 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6+7+8 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + { + boost::shared_ptr< X > pi = boost::allocate_shared< X >( cxx11_allocator(), 1, 2, 3, 4, 5, 6, 7, 8, 9 ); + boost::weak_ptr wp( pi ); + + BOOST_TEST( X::instances == 1 ); + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( pi->v == 1+2+3+4+5+6+7+8+9 ); + + pi.reset(); + + BOOST_TEST( X::instances == 0 ); + } + + return boost::report_errors(); +} + +#else // !defined( BOOST_NO_CXX11_ALLOCATOR ) + +int main() +{ + return 0; +} + +#endif