diff --git a/include/boost/smart_ptr/detail/local_counted_base.hpp b/include/boost/smart_ptr/detail/local_counted_base.hpp index df652b3..f5a5244 100644 --- a/include/boost/smart_ptr/detail/local_counted_base.hpp +++ b/include/boost/smart_ptr/detail/local_counted_base.hpp @@ -55,9 +55,9 @@ public: { } - virtual void destroy() BOOST_SP_NOEXCEPT = 0; + virtual void local_cb_destroy() BOOST_SP_NOEXCEPT = 0; - virtual boost::shared_ptr get_shared_ptr() const BOOST_SP_NOEXCEPT = 0; + virtual boost::shared_ptr local_cb_get_shared_ptr() const BOOST_SP_NOEXCEPT = 0; void add_ref() BOOST_SP_NOEXCEPT { @@ -78,7 +78,7 @@ public: if( local_use_count_ == 0 ) { - destroy(); + local_cb_destroy(); } } @@ -112,12 +112,12 @@ public: #endif - virtual void destroy() BOOST_SP_NOEXCEPT + virtual void local_cb_destroy() BOOST_SP_NOEXCEPT { delete this; } - virtual boost::shared_ptr get_shared_ptr() const BOOST_SP_NOEXCEPT + virtual boost::shared_ptr local_cb_get_shared_ptr() const BOOST_SP_NOEXCEPT { return const_pointer_cast( pn_ ); } @@ -129,12 +129,12 @@ public: boost::shared_ptr pn_; - virtual void destroy() BOOST_SP_NOEXCEPT + virtual void local_cb_destroy() BOOST_SP_NOEXCEPT { pn_.reset(); } - virtual boost::shared_ptr get_shared_ptr() const BOOST_SP_NOEXCEPT + virtual boost::shared_ptr local_cb_get_shared_ptr() const BOOST_SP_NOEXCEPT { return const_pointer_cast( pn_ ); } diff --git a/include/boost/smart_ptr/local_shared_ptr.hpp b/include/boost/smart_ptr/local_shared_ptr.hpp index ffd273e..d7a1278 100644 --- a/include/boost/smart_ptr/local_shared_ptr.hpp +++ b/include/boost/smart_ptr/local_shared_ptr.hpp @@ -132,6 +132,10 @@ template< class E, class P, class D, class A > inline void lsp_allocator_constru pn = pd; } +struct lsp_internal_constructor_tag +{ +}; + } // namespace detail // @@ -184,6 +188,11 @@ public: #endif + // internal constructor, used by make_shared + BOOST_CONSTEXPR local_shared_ptr( boost::detail::lsp_internal_constructor_tag, T * px_, boost::detail::local_counted_base * pn_ ) BOOST_SP_NOEXCEPT : px( px_ ), pn( pn_ ) + { + } + template explicit local_shared_ptr( Y * p ): px( p ), pn( 0 ) { @@ -484,7 +493,7 @@ public: if( pn ) { - return static_pointer_cast( pn->get_shared_ptr() ); + return static_pointer_cast( pn->local_cb_get_shared_ptr() ); } else { @@ -502,7 +511,7 @@ public: if( pn ) { - return static_pointer_cast( pn->get_shared_ptr() ); + return static_pointer_cast( pn->local_cb_get_shared_ptr() ); } else { diff --git a/include/boost/smart_ptr/make_local_shared_object.hpp b/include/boost/smart_ptr/make_local_shared_object.hpp index 9605cfe..c8a2330 100644 --- a/include/boost/smart_ptr/make_local_shared_object.hpp +++ b/include/boost/smart_ptr/make_local_shared_object.hpp @@ -12,6 +12,7 @@ // See http://www.boost.org/libs/smart_ptr/ for documentation. #include +#include #include #include #include @@ -23,6 +24,8 @@ namespace boost namespace detail { +// lsp_if_not_array + template struct lsp_if_not_array { typedef boost::local_shared_ptr type; @@ -36,26 +39,142 @@ template struct lsp_if_not_array { }; +// lsp_ms_deleter + +template class lsp_ms_deleter: public local_counted_impl_em +{ +private: + + typedef typename sp_aligned_storage::value>::type storage_type; + + storage_type storage_; + A a_; + bool initialized_; + +private: + + void destroy() BOOST_SP_NOEXCEPT + { + 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: + + explicit lsp_ms_deleter( A const & a ) BOOST_SP_NOEXCEPT : a_( a ), initialized_( false ) + { + } + + // optimization: do not copy storage_ + lsp_ms_deleter( lsp_ms_deleter const & r ) BOOST_SP_NOEXCEPT : a_( r.a_), initialized_( false ) + { + } + + ~lsp_ms_deleter() BOOST_SP_NOEXCEPT + { + destroy(); + } + + void operator()( T * ) BOOST_SP_NOEXCEPT + { + destroy(); + } + + static void operator_fn( T* ) BOOST_SP_NOEXCEPT // operator() can't be static + { + } + + void * address() BOOST_SP_NOEXCEPT + { + return storage_.data_; + } + + void set_initialized() BOOST_SP_NOEXCEPT + { + initialized_ = true; + } +}; + } // namespace detail -template typename boost::detail::lsp_if_not_array::type make_local_shared( Args&&... args ) -{ - return boost::make_shared( std::forward(args)... ); -} - -template typename boost::detail::lsp_if_not_array::type make_local_shared_noinit() -{ - return boost::make_shared_noinit(); -} - template typename boost::detail::lsp_if_not_array::type allocate_local_shared( A const & a, Args&&... args ) { - return boost::allocate_shared( a, std::forward(args)... ); + typedef typename std::allocator_traits::template rebind_alloc A2; + A2 a2( a ); + + typedef boost::detail::lsp_ms_deleter D; + + boost::shared_ptr pt( static_cast< T* >( 0 ), boost::detail::sp_inplace_tag(), a2 ); + + 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 ), std::forward( args )... ); + +#else + + ::new( pv ) T( std::forward( args )... ); + +#endif + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + + pd->pn_ = boost::shared_ptr( pt, pt2 ); + + return boost::local_shared_ptr( boost::detail::lsp_internal_constructor_tag(), pt2, pd ); } template typename boost::detail::lsp_if_not_array::type allocate_local_shared_noinit( A const & a ) { - return boost::allocate_shared_noinit( a ); + typedef typename std::allocator_traits::template rebind_alloc A2; + A2 a2( a ); + + typedef boost::detail::lsp_ms_deleter D; + + boost::shared_ptr pt( static_cast< T* >( 0 ), boost::detail::sp_inplace_tag(), a2 ); + + D * pd = static_cast< D* >( pt._internal_get_untyped_deleter() ); + void * pv = pd->address(); + + ::new( pv ) T; + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + + pd->pn_ = boost::shared_ptr( pt, pt2 ); + + return boost::local_shared_ptr( boost::detail::lsp_internal_constructor_tag(), pt2, pd ); +} + +template typename boost::detail::lsp_if_not_array::type make_local_shared( Args&&... args ) +{ + return boost::allocate_local_shared( std::allocator(), std::forward(args)... ); +} + +template typename boost::detail::lsp_if_not_array::type make_local_shared_noinit() +{ + return boost::allocate_shared_noinit( std::allocator() ); } } // namespace boost diff --git a/test/allocate_local_shared_esft_test.cpp b/test/allocate_local_shared_esft_test.cpp index 4531434..65349c5 100644 --- a/test/allocate_local_shared_esft_test.cpp +++ b/test/allocate_local_shared_esft_test.cpp @@ -48,21 +48,21 @@ int X::instances = 0; int main() { - BOOST_TEST( X::instances == 0 ); + BOOST_TEST_EQ( X::instances, 0 ); { boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator() ); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); try { boost::shared_ptr< X > qx = px->shared_from_this(); - BOOST_TEST( px == qx ); + BOOST_TEST_EQ( px, qx ); BOOST_TEST( !( px < qx ) && !( qx < px ) ); px.reset(); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); } catch( boost::bad_weak_ptr const& ) { @@ -70,21 +70,43 @@ int main() } } - BOOST_TEST( X::instances == 0 ); + BOOST_TEST_EQ( X::instances, 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_local_shared_noinit< X >( std::allocator() ); + BOOST_TEST_EQ( X::instances, 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST_EQ( px, qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST_EQ( X::instances, 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST_EQ( X::instances, 0 ); { boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1 ); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); try { boost::shared_ptr< X > qx = px->shared_from_this(); - BOOST_TEST( px == qx ); + BOOST_TEST_EQ( px, qx ); BOOST_TEST( !( px < qx ) && !( qx < px ) ); px.reset(); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); } catch( boost::bad_weak_ptr const& ) { @@ -92,21 +114,21 @@ int main() } } - BOOST_TEST( X::instances == 0 ); + BOOST_TEST_EQ( X::instances, 0 ); { boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2 ); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); try { boost::shared_ptr< X > qx = px->shared_from_this(); - BOOST_TEST( px == qx ); + BOOST_TEST_EQ( px, qx ); BOOST_TEST( !( px < qx ) && !( qx < px ) ); px.reset(); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); } catch( boost::bad_weak_ptr const& ) { @@ -114,21 +136,21 @@ int main() } } - BOOST_TEST( X::instances == 0 ); + BOOST_TEST_EQ( X::instances, 0 ); { boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3 ); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); try { boost::shared_ptr< X > qx = px->shared_from_this(); - BOOST_TEST( px == qx ); + BOOST_TEST_EQ( px, qx ); BOOST_TEST( !( px < qx ) && !( qx < px ) ); px.reset(); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); } catch( boost::bad_weak_ptr const& ) { @@ -136,21 +158,21 @@ int main() } } - BOOST_TEST( X::instances == 0 ); + BOOST_TEST_EQ( X::instances, 0 ); { boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4 ); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); try { boost::shared_ptr< X > qx = px->shared_from_this(); - BOOST_TEST( px == qx ); + BOOST_TEST_EQ( px, qx ); BOOST_TEST( !( px < qx ) && !( qx < px ) ); px.reset(); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); } catch( boost::bad_weak_ptr const& ) { @@ -158,21 +180,21 @@ int main() } } - BOOST_TEST( X::instances == 0 ); + BOOST_TEST_EQ( X::instances, 0 ); { boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5 ); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); try { boost::shared_ptr< X > qx = px->shared_from_this(); - BOOST_TEST( px == qx ); + BOOST_TEST_EQ( px, qx ); BOOST_TEST( !( px < qx ) && !( qx < px ) ); px.reset(); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); } catch( boost::bad_weak_ptr const& ) { @@ -180,21 +202,21 @@ int main() } } - BOOST_TEST( X::instances == 0 ); + BOOST_TEST_EQ( X::instances, 0 ); { boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6 ); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); try { boost::shared_ptr< X > qx = px->shared_from_this(); - BOOST_TEST( px == qx ); + BOOST_TEST_EQ( px, qx ); BOOST_TEST( !( px < qx ) && !( qx < px ) ); px.reset(); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); } catch( boost::bad_weak_ptr const& ) { @@ -202,21 +224,21 @@ int main() } } - BOOST_TEST( X::instances == 0 ); + BOOST_TEST_EQ( X::instances, 0 ); { boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7 ); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); try { boost::shared_ptr< X > qx = px->shared_from_this(); - BOOST_TEST( px == qx ); + BOOST_TEST_EQ( px, qx ); BOOST_TEST( !( px < qx ) && !( qx < px ) ); px.reset(); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); } catch( boost::bad_weak_ptr const& ) { @@ -224,21 +246,21 @@ int main() } } - BOOST_TEST( X::instances == 0 ); + BOOST_TEST_EQ( X::instances, 0 ); { boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7, 8 ); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); try { boost::shared_ptr< X > qx = px->shared_from_this(); - BOOST_TEST( px == qx ); + BOOST_TEST_EQ( px, qx ); BOOST_TEST( !( px < qx ) && !( qx < px ) ); px.reset(); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); } catch( boost::bad_weak_ptr const& ) { @@ -246,21 +268,21 @@ int main() } } - BOOST_TEST( X::instances == 0 ); + BOOST_TEST_EQ( X::instances, 0 ); { boost::shared_ptr< X > px = boost::allocate_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7, 8, 9 ); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); try { boost::shared_ptr< X > qx = px->shared_from_this(); - BOOST_TEST( px == qx ); + BOOST_TEST_EQ( px, qx ); BOOST_TEST( !( px < qx ) && !( qx < px ) ); px.reset(); - BOOST_TEST( X::instances == 1 ); + BOOST_TEST_EQ( X::instances, 1 ); } catch( boost::bad_weak_ptr const& ) { @@ -268,7 +290,7 @@ int main() } } - BOOST_TEST( X::instances == 0 ); + BOOST_TEST_EQ( X::instances, 0 ); return boost::report_errors(); } diff --git a/test/allocate_shared_esft_test.cpp b/test/allocate_shared_esft_test.cpp index 2bb8ccc..7902313 100644 --- a/test/allocate_shared_esft_test.cpp +++ b/test/allocate_shared_esft_test.cpp @@ -62,6 +62,28 @@ int main() BOOST_TEST( X::instances == 0 ); + { + boost::shared_ptr< X > px = boost::allocate_shared_noinit< X >( std::allocator() ); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + { boost::shared_ptr< X > px = boost::allocate_shared< X >( std::allocator(), 1 ); BOOST_TEST( X::instances == 1 ); diff --git a/test/allocate_shared_test.cpp b/test/allocate_shared_test.cpp index bdae793..31dcc7b 100644 --- a/test/allocate_shared_test.cpp +++ b/test/allocate_shared_test.cpp @@ -61,6 +61,12 @@ int main() BOOST_TEST( *pi == 0 ); } + { + boost::shared_ptr< int > pi = boost::allocate_shared_noinit< int >( std::allocator() ); + + BOOST_TEST( pi.get() != 0 ); + } + { boost::shared_ptr< int > pi = boost::allocate_shared< int >( std::allocator(), 5 ); @@ -83,6 +89,19 @@ int main() BOOST_TEST( X::instances == 0 ); } + { + boost::shared_ptr< X > pi = boost::allocate_shared_noinit< X >( std::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 >( std::allocator(), 1 ); boost::weak_ptr wp( pi ); diff --git a/test/make_local_shared_esft_test.cpp b/test/make_local_shared_esft_test.cpp index 602aaf3..95b651e 100644 --- a/test/make_local_shared_esft_test.cpp +++ b/test/make_local_shared_esft_test.cpp @@ -71,6 +71,28 @@ int main() BOOST_TEST( X::instances == 0 ); + { + boost::shared_ptr< X > px = boost::make_local_shared_noinit< X >(); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + { boost::shared_ptr< X > px = boost::make_local_shared< X >( 1 ); BOOST_TEST( X::instances == 1 ); diff --git a/test/make_shared_esft_test.cpp b/test/make_shared_esft_test.cpp index 1956cba..cbd31d0 100644 --- a/test/make_shared_esft_test.cpp +++ b/test/make_shared_esft_test.cpp @@ -61,6 +61,28 @@ int main() BOOST_TEST( X::instances == 0 ); + { + boost::shared_ptr< X > px = boost::make_shared_noinit< X >(); + BOOST_TEST( X::instances == 1 ); + + try + { + boost::shared_ptr< X > qx = px->shared_from_this(); + + BOOST_TEST( px == qx ); + BOOST_TEST( !( px < qx ) && !( qx < px ) ); + + px.reset(); + BOOST_TEST( X::instances == 1 ); + } + catch( boost::bad_weak_ptr const& ) + { + BOOST_ERROR( "px->shared_from_this() failed" ); + } + } + + BOOST_TEST( X::instances == 0 ); + { boost::shared_ptr< X > px = boost::make_shared< X >( 1 ); BOOST_TEST( X::instances == 1 ); diff --git a/test/make_shared_test.cpp b/test/make_shared_test.cpp index 9ebc3fa..aff9b7c 100644 --- a/test/make_shared_test.cpp +++ b/test/make_shared_test.cpp @@ -61,6 +61,12 @@ int main() BOOST_TEST( *pi == 0 ); } + { + boost::shared_ptr< int > pi = boost::make_shared_noinit< int >(); + + BOOST_TEST( pi.get() != 0 ); + } + { boost::shared_ptr< int > pi = boost::make_shared< int >( 5 ); @@ -83,6 +89,19 @@ int main() BOOST_TEST( X::instances == 0 ); } + { + boost::shared_ptr< X > pi = boost::make_shared_noinit< X >(); + 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::make_shared< X >( 1 ); boost::weak_ptr wp( pi );