From edf02ab0f90796ed8673b7c68641463a87b11eee Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 19 Jun 2017 01:05:01 +0300 Subject: [PATCH 01/13] Add more tests --- include/boost/smart_ptr/local_shared_ptr.hpp | 4 +- test/local_sp_test.cpp | 320 ++++++++++++++++++- 2 files changed, 319 insertions(+), 5 deletions(-) diff --git a/include/boost/smart_ptr/local_shared_ptr.hpp b/include/boost/smart_ptr/local_shared_ptr.hpp index d0e1721..ffd273e 100644 --- a/include/boost/smart_ptr/local_shared_ptr.hpp +++ b/include/boost/smart_ptr/local_shared_ptr.hpp @@ -46,14 +46,14 @@ public: #endif - template void operator()( Y* p ) const BOOST_SP_NOEXCEPT + template void operator()( Y* p ) BOOST_SP_NOEXCEPT { d_( p ); } #if !defined( BOOST_NO_CXX11_NULLPTR ) - void operator()( boost::detail::sp_nullptr_t p ) const BOOST_SP_NOEXCEPT + void operator()( boost::detail::sp_nullptr_t p ) BOOST_SP_NOEXCEPT { d_( p ); } diff --git a/test/local_sp_test.cpp b/test/local_sp_test.cpp index b31d498..f91163f 100644 --- a/test/local_sp_test.cpp +++ b/test/local_sp_test.cpp @@ -1679,6 +1679,320 @@ static void shared_ptr_move_assignment() #endif +// unique_ptr assignment + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) && !defined( BOOST_NO_CXX11_SMART_PTR ) + +template static void empty_unique_ptr_assign_test() +{ + boost::local_shared_ptr p2; + + p2 = std::unique_ptr(); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); + + boost::local_shared_ptr p3; + + p3 = std::unique_ptr(); + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); + + boost::local_shared_ptr p4; + + p4 = std::unique_ptr(); + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); + + boost::local_shared_ptr p5; + + p5 = std::unique_ptr(); + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); +} + +template static void empty_unique_ptr_assign_test_() +{ + boost::local_shared_ptr p2( static_cast(0) ); + + p2 = std::unique_ptr(); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.local_use_count(), 0 ); + + boost::local_shared_ptr p3( static_cast(0) ); + + p3 = std::unique_ptr(); + + BOOST_TEST_EQ( p3.get(), static_cast(0) ); + BOOST_TEST_EQ( p3.local_use_count(), 0 ); + + boost::local_shared_ptr p4( static_cast(0) ); + + p4 = std::unique_ptr(); + + BOOST_TEST_EQ( p4.get(), static_cast(0) ); + BOOST_TEST_EQ( p4.local_use_count(), 0 ); + + boost::local_shared_ptr p5( static_cast(0) ); + + p5 = std::unique_ptr(); + + BOOST_TEST_EQ( p5.get(), static_cast(0) ); + BOOST_TEST_EQ( p5.local_use_count(), 0 ); +} + +template static void test_nonempty_unique_ptr_assign( boost::local_shared_ptr p2, std::unique_ptr && p1 ) +{ + U* q = p1.get(); + + p2 = std::move( p1 ); + + BOOST_TEST_EQ( p2.get(), q ); + BOOST_TEST_EQ( p2.local_use_count(), 1 ); + + BOOST_TEST( p1.get() == 0 ); +} + +template static void new_unique_ptr_assign_test() +{ + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); + + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr( new T() ) ); + + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T() ), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T const() ), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T volatile() ), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T const volatile() ), std::unique_ptr( new T() ) ); + + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr( new T() ) ); +} + +template static void del_unique_ptr_assign_test() +{ + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); + + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( static_cast(0) ), std::unique_ptr>( new T() ) ); + + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T() ), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T const() ), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T volatile() ), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr( new T const volatile() ), std::unique_ptr>( new T() ) ); + + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); + test_nonempty_unique_ptr_assign( boost::local_shared_ptr(), std::unique_ptr>( new T() ) ); +} + +static void unique_ptr_assignment() +{ + empty_unique_ptr_assign_test(); + empty_unique_ptr_assign_test_(); + empty_unique_ptr_assign_test(); + empty_unique_ptr_assign_test_(); + + BOOST_TEST( X::instances == 0 ); + + new_unique_ptr_assign_test(); + new_unique_ptr_assign_test(); + + BOOST_TEST( X::instances == 0 ); + + del_unique_ptr_assign_test(); + del_unique_ptr_assign_test(); + + BOOST_TEST( X::instances == 0 ); +} + +#else + +static void unique_ptr_assignment() +{ +} + +#endif + +// pointer reset + +template static void test_pointer_reset( boost::local_shared_ptr p2 ) +{ + T * q = new T(); + + p2.reset( q ); + + BOOST_TEST_EQ( p2.get(), q ); + BOOST_TEST_EQ( p2.local_use_count(), 1 ); +} + +template static void empty_pointer_reset_test() +{ + test_pointer_reset( boost::local_shared_ptr() ); + test_pointer_reset( boost::local_shared_ptr() ); + test_pointer_reset( boost::local_shared_ptr() ); + test_pointer_reset( boost::local_shared_ptr() ); + + test_pointer_reset( boost::local_shared_ptr() ); + test_pointer_reset( boost::local_shared_ptr() ); + test_pointer_reset( boost::local_shared_ptr() ); + test_pointer_reset( boost::local_shared_ptr() ); +} + +template static void null_pointer_reset_test() +{ + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); + + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_pointer_reset( boost::local_shared_ptr( static_cast(0) ) ); +} + +template static void new_pointer_reset_test() +{ + test_pointer_reset( boost::local_shared_ptr( new T() ) ); + test_pointer_reset( boost::local_shared_ptr( new T() ) ); + test_pointer_reset( boost::local_shared_ptr( new T() ) ); + test_pointer_reset( boost::local_shared_ptr( new T() ) ); + + test_pointer_reset( boost::local_shared_ptr( new T() ) ); + test_pointer_reset( boost::local_shared_ptr( new T() ) ); + test_pointer_reset( boost::local_shared_ptr( new T() ) ); + test_pointer_reset( boost::local_shared_ptr( new T() ) ); +} + +static void pointer_reset() +{ + empty_pointer_reset_test(); + empty_pointer_reset_test(); + + BOOST_TEST( X::instances == 0 ); + + null_pointer_reset_test(); + null_pointer_reset_test(); + + BOOST_TEST( X::instances == 0 ); + + new_pointer_reset_test(); + new_pointer_reset_test(); + + BOOST_TEST( X::instances == 0 ); +} + +// deleter reset + +template class deleter +{ +private: + + bool * called_; + +public: + + explicit deleter( bool * called ): called_( called ) {} + void operator()( T * p ) { *called_ = true; delete p; } +}; + +template static void test_deleter_reset( boost::local_shared_ptr p2 ) +{ + T * q = new T(); + + bool called = false; + + p2.reset( q, deleter( &called ) ); + + BOOST_TEST_EQ( p2.get(), q ); + BOOST_TEST_EQ( p2.local_use_count(), 1 ); + + boost::shared_ptr p3( p2 ); + + // BOOST_TEST( boost::get_deleter< deleter >( p3 ) != 0 ); + + p3.reset(); + BOOST_TEST( !called ); + + p2.reset(); + BOOST_TEST( called ); +} + +template static void empty_deleter_reset_test() +{ + test_deleter_reset( boost::local_shared_ptr() ); + test_deleter_reset( boost::local_shared_ptr() ); + test_deleter_reset( boost::local_shared_ptr() ); + test_deleter_reset( boost::local_shared_ptr() ); + + test_deleter_reset( boost::local_shared_ptr() ); + test_deleter_reset( boost::local_shared_ptr() ); + test_deleter_reset( boost::local_shared_ptr() ); + test_deleter_reset( boost::local_shared_ptr() ); +} + +template static void null_deleter_reset_test() +{ + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); + + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_deleter_reset( boost::local_shared_ptr( static_cast(0) ) ); +} + +template static void new_deleter_reset_test() +{ + test_deleter_reset( boost::local_shared_ptr( new T() ) ); + test_deleter_reset( boost::local_shared_ptr( new T() ) ); + test_deleter_reset( boost::local_shared_ptr( new T() ) ); + test_deleter_reset( boost::local_shared_ptr( new T() ) ); + + test_deleter_reset( boost::local_shared_ptr( new T() ) ); + test_deleter_reset( boost::local_shared_ptr( new T() ) ); + test_deleter_reset( boost::local_shared_ptr( new T() ) ); + test_deleter_reset( boost::local_shared_ptr( new T() ) ); +} + +static void deleter_reset() +{ + empty_deleter_reset_test(); + empty_deleter_reset_test(); + + BOOST_TEST( X::instances == 0 ); + + null_deleter_reset_test(); + null_deleter_reset_test(); + + BOOST_TEST( X::instances == 0 ); + + new_deleter_reset_test(); + new_deleter_reset_test(); + + BOOST_TEST( X::instances == 0 ); +} + // main int main() @@ -1702,11 +2016,11 @@ int main() nullptr_assignment(); shared_ptr_copy_assignment(); shared_ptr_move_assignment(); - // unique_ptr_assignment(); + unique_ptr_assignment(); default_reset(); - // pointer_reset(); - // deleter_reset(); + pointer_reset(); + deleter_reset(); // allocator_reset(); // aliasing_reset(); From f7275b7f4597a546fbed9dc02dc547ea965774af Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 19 Jun 2017 02:30:54 +0300 Subject: [PATCH 02/13] Add more tests --- test/local_sp_test.cpp | 315 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 312 insertions(+), 3 deletions(-) diff --git a/test/local_sp_test.cpp b/test/local_sp_test.cpp index f91163f..4d447b7 100644 --- a/test/local_sp_test.cpp +++ b/test/local_sp_test.cpp @@ -1993,6 +1993,315 @@ static void deleter_reset() BOOST_TEST( X::instances == 0 ); } +// allocator reset + +template static void test_allocator_reset( boost::local_shared_ptr p2 ) +{ + T * q = new T(); + + bool called = false; + + p2.reset( q, deleter( &called ), std::allocator() ); + + BOOST_TEST_EQ( p2.get(), q ); + BOOST_TEST_EQ( p2.local_use_count(), 1 ); + + boost::shared_ptr p3( p2 ); + + // BOOST_TEST( boost::get_deleter< deleter >( p3 ) != 0 ); + + p3.reset(); + BOOST_TEST( !called ); + + p2.reset(); + BOOST_TEST( called ); +} + +template static void empty_allocator_reset_test() +{ + test_allocator_reset( boost::local_shared_ptr() ); + test_allocator_reset( boost::local_shared_ptr() ); + test_allocator_reset( boost::local_shared_ptr() ); + test_allocator_reset( boost::local_shared_ptr() ); + + test_allocator_reset( boost::local_shared_ptr() ); + test_allocator_reset( boost::local_shared_ptr() ); + test_allocator_reset( boost::local_shared_ptr() ); + test_allocator_reset( boost::local_shared_ptr() ); +} + +template static void null_allocator_reset_test() +{ + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); + + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); + test_allocator_reset( boost::local_shared_ptr( static_cast(0) ) ); +} + +template static void new_allocator_reset_test() +{ + test_allocator_reset( boost::local_shared_ptr( new T() ) ); + test_allocator_reset( boost::local_shared_ptr( new T() ) ); + test_allocator_reset( boost::local_shared_ptr( new T() ) ); + test_allocator_reset( boost::local_shared_ptr( new T() ) ); + + test_allocator_reset( boost::local_shared_ptr( new T() ) ); + test_allocator_reset( boost::local_shared_ptr( new T() ) ); + test_allocator_reset( boost::local_shared_ptr( new T() ) ); + test_allocator_reset( boost::local_shared_ptr( new T() ) ); +} + +static void allocator_reset() +{ + empty_allocator_reset_test(); + empty_allocator_reset_test(); + + BOOST_TEST( X::instances == 0 ); + + null_allocator_reset_test(); + null_allocator_reset_test(); + + BOOST_TEST( X::instances == 0 ); + + new_allocator_reset_test(); + new_allocator_reset_test(); + + BOOST_TEST( X::instances == 0 ); +} + +// aliasing reset + +struct null_deleter +{ + void operator()( void const volatile* ) {} +}; + +template void test_aliasing_reset_( boost::local_shared_ptr const & p1, U * p2 ) +{ + boost::local_shared_ptr p3( static_cast(0), null_deleter() ); + + p3.reset( p1, p2 ); + + BOOST_TEST( p3.get() == p2 ); + BOOST_TEST( p3.local_use_count() == p1.local_use_count() ); + BOOST_TEST( !p3.owner_before( p1 ) && !p1.owner_before( p3 ) ); +} + +template void test_01_aliasing_reset_() +{ + U u; + boost::local_shared_ptr p1; + + test_aliasing_reset_( p1, &u ); +} + +template void test_01_aliasing_reset() +{ + test_01_aliasing_reset_(); + test_01_aliasing_reset_(); + test_01_aliasing_reset_(); + test_01_aliasing_reset_(); + + test_01_aliasing_reset_(); + test_01_aliasing_reset_(); + test_01_aliasing_reset_(); + test_01_aliasing_reset_(); +} + +template void test_10_aliasing_reset_() +{ + boost::local_shared_ptr p1( new T() ); + test_aliasing_reset_( p1, static_cast(0) ); +} + +template void test_10_aliasing_reset() +{ + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); + test_10_aliasing_reset_(); +} + +template void test_11_aliasing_reset_() +{ + U u; + boost::local_shared_ptr p1( new T() ); + + test_aliasing_reset_( p1, &u ); +} + +template void test_11_aliasing_reset() +{ + test_11_aliasing_reset_(); + test_11_aliasing_reset_(); + test_11_aliasing_reset_(); + test_11_aliasing_reset_(); + + test_11_aliasing_reset_(); + test_11_aliasing_reset_(); + test_11_aliasing_reset_(); + test_11_aliasing_reset_(); +} + +static void aliasing_reset() +{ + test_01_aliasing_reset(); + test_10_aliasing_reset(); + test_11_aliasing_reset(); + + test_01_aliasing_reset(); + + test_10_aliasing_reset(); + + test_10_aliasing_reset(); + + test_01_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_10_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_11_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_01_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_10_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_11_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_01_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_10_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_11_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_01_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_10_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); + + test_10_aliasing_reset(); + BOOST_TEST( X::instances == 0 ); +} + +// element access + +template static void empty_element_access_() +{ + boost::local_shared_ptr p1; + + BOOST_TEST_EQ( p1.operator->(), static_cast(0) ); + BOOST_TEST_EQ( p1.get(), static_cast(0) ); + BOOST_TEST( p1? false: true ); + BOOST_TEST( !p1 ); + BOOST_TEST_EQ( p1.local_use_count(), 0 ); +} + +template static void empty_element_access() +{ + empty_element_access_(); + empty_element_access_(); + empty_element_access_(); + empty_element_access_(); +} + +template static void new_element_access_() +{ + { + T * p0 = new T(); + boost::local_shared_ptr p1( p0 ); + + BOOST_TEST_EQ( p1.operator->(), p0 ); + BOOST_TEST_EQ( p1.get(), p0 ); + BOOST_TEST_EQ( &*p1, p0 ); + BOOST_TEST( p1? true: false ); + BOOST_TEST_NOT( !p1 ); + BOOST_TEST_EQ( p1.local_use_count(), 1 ); + } + + { + T * p0 = new T[3](); + boost::local_shared_ptr p1( p0 ); + + BOOST_TEST_EQ( p1.get(), p0 ); + + BOOST_TEST_EQ( &p1[0], &p0[0] ); + BOOST_TEST_EQ( &p1[1], &p0[1] ); + BOOST_TEST_EQ( &p1[2], &p0[2] ); + + BOOST_TEST( p1? true: false ); + BOOST_TEST_NOT( !p1 ); + BOOST_TEST_EQ( p1.local_use_count(), 1 ); + } + + { + T * p0 = new T[3](); + boost::local_shared_ptr p1( p0 ); + + BOOST_TEST_EQ( p1.get(), p0 ); + + BOOST_TEST_EQ( &p1[0], &p0[0] ); + BOOST_TEST_EQ( &p1[1], &p0[1] ); + BOOST_TEST_EQ( &p1[2], &p0[2] ); + + BOOST_TEST( p1? true: false ); + BOOST_TEST_NOT( !p1 ); + BOOST_TEST_EQ( p1.local_use_count(), 1 ); + } +} + +template static void new_element_access() +{ + new_element_access_(); + new_element_access_(); + new_element_access_(); + new_element_access_(); +} + +static void element_access() +{ + empty_element_access(); + empty_element_access(); + + BOOST_TEST( X::instances == 0 ); + + empty_element_access(); + empty_element_access(); + + new_element_access(); + new_element_access(); + + BOOST_TEST( X::instances == 0 ); +} + // main int main() @@ -2021,10 +2330,10 @@ int main() default_reset(); pointer_reset(); deleter_reset(); - // allocator_reset(); - // aliasing_reset(); + allocator_reset(); + aliasing_reset(); - // element_access(); + element_access(); // swap_test(); // owner_before_test(); // equal_test(); From 68fb786d4d618b90fe49894b13789afdf57d82bf Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 19 Jun 2017 17:36:13 +0300 Subject: [PATCH 03/13] Add more tests --- test/local_sp_test.cpp | 189 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) diff --git a/test/local_sp_test.cpp b/test/local_sp_test.cpp index 4d447b7..dd161d8 100644 --- a/test/local_sp_test.cpp +++ b/test/local_sp_test.cpp @@ -9,6 +9,8 @@ // #include +#include +#include #include struct X @@ -2302,6 +2304,186 @@ static void element_access() BOOST_TEST( X::instances == 0 ); } +// shared_ptr conversion + +template static void empty_shared_ptr_conversion_() +{ + boost::local_shared_ptr p1; + boost::shared_ptr p2( p1 ); + + BOOST_TEST_EQ( p2.get(), static_cast(0) ); + BOOST_TEST_EQ( p2.use_count(), 0 ); +} + +template static void empty_shared_ptr_conversion() +{ + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); + empty_shared_ptr_conversion_(); +} + +template static void new_shared_ptr_conversion_() +{ + boost::local_shared_ptr p1( new T() ); + boost::shared_ptr p2( p1 ); + + BOOST_TEST_EQ( p2.get(), p1.get() ); + BOOST_TEST_EQ( p2.use_count(), 2 ); + + boost::shared_ptr p3( p1 ); + + BOOST_TEST_EQ( p3.get(), p1.get() ); + BOOST_TEST_EQ( p3.use_count(), 3 ); + BOOST_TEST( !(p2 < p3) && !(p3 < p2) ); + + BOOST_TEST_EQ( p1.local_use_count(), 1 ); + + p1.reset(); + + BOOST_TEST_EQ( p2.use_count(), 2 ); + BOOST_TEST_EQ( p3.use_count(), 2 ); +} + +template static void new_shared_ptr_conversion() +{ + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); + new_shared_ptr_conversion_(); +} + +static void shared_ptr_conversion() +{ + empty_shared_ptr_conversion(); + empty_shared_ptr_conversion(); + empty_shared_ptr_conversion(); + empty_shared_ptr_conversion(); + + BOOST_TEST( X::instances == 0 ); + + new_shared_ptr_conversion(); + new_shared_ptr_conversion(); + + BOOST_TEST( X::instances == 0 ); +} + +// weak_ptr conversion + +template static void empty_weak_ptr_conversion_() +{ + boost::local_shared_ptr p1; + boost::weak_ptr p2( p1 ); + + BOOST_TEST_EQ( p2.lock().get(), static_cast(0) ); + BOOST_TEST_EQ( p2.use_count(), 0 ); +} + +template static void empty_weak_ptr_conversion() +{ + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); + empty_weak_ptr_conversion_(); +} + +template static void new_weak_ptr_conversion_() +{ + boost::local_shared_ptr p1( new T() ); + boost::weak_ptr p2( p1 ); + + BOOST_TEST_EQ( p2.lock().get(), p1.get() ); + BOOST_TEST_EQ( p2.use_count(), 1 ); + + boost::weak_ptr p3( p1 ); + + BOOST_TEST_EQ( p3.lock().get(), p1.get() ); + BOOST_TEST_EQ( p3.use_count(), 1 ); + BOOST_TEST( !(p2 < p3) && !(p3 < p2) ); + + BOOST_TEST_EQ( p1.local_use_count(), 1 ); + + p1.reset(); + + BOOST_TEST_EQ( p2.use_count(), 0 ); + BOOST_TEST_EQ( p3.use_count(), 0 ); +} + +template static void new_weak_ptr_conversion() +{ + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); + new_weak_ptr_conversion_(); +} + +static void weak_ptr_conversion() +{ + empty_weak_ptr_conversion(); + empty_weak_ptr_conversion(); + empty_weak_ptr_conversion(); + empty_weak_ptr_conversion(); + + BOOST_TEST( X::instances == 0 ); + + new_weak_ptr_conversion(); + new_weak_ptr_conversion(); + + BOOST_TEST( X::instances == 0 ); +} + // main int main() @@ -2334,9 +2516,16 @@ int main() aliasing_reset(); element_access(); + shared_ptr_conversion(); + weak_ptr_conversion(); // swap_test(); // owner_before_test(); // equal_test(); + // operator< ? + // casts + // get_pointer + // operator<< + // hash return boost::report_errors(); } From 6218c52c1a983ce56ec0feb8ff6d4f7b9cea780c Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 20 Jun 2017 01:42:45 +0300 Subject: [PATCH 04/13] Add make_local_shared --- include/boost/smart_ptr/make_local_shared.hpp | 17 ++ .../smart_ptr/make_local_shared_array.hpp | 63 ++++ .../smart_ptr/make_local_shared_object.hpp | 63 ++++ test/Jamfile.v2 | 3 + test/make_local_shared_esft_test.cpp | 275 ++++++++++++++++++ test/make_local_shared_test.cpp | 216 ++++++++++++++ 6 files changed, 637 insertions(+) create mode 100644 include/boost/smart_ptr/make_local_shared.hpp create mode 100644 include/boost/smart_ptr/make_local_shared_array.hpp create mode 100644 include/boost/smart_ptr/make_local_shared_object.hpp create mode 100644 test/make_local_shared_esft_test.cpp create mode 100644 test/make_local_shared_test.cpp diff --git a/include/boost/smart_ptr/make_local_shared.hpp b/include/boost/smart_ptr/make_local_shared.hpp new file mode 100644 index 0000000..23114fe --- /dev/null +++ b/include/boost/smart_ptr/make_local_shared.hpp @@ -0,0 +1,17 @@ +#ifndef BOOST_SMART_PTR_MAKE_LOCAL_SHARED_HPP_INCLUDED +#define BOOST_SMART_PTR_MAKE_LOCAL_SHARED_HPP_INCLUDED + +// make_local_shared.hpp +// +// Copyright 2017 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 +// +// See http://www.boost.org/libs/smart_ptr/ for documentation. + +#include +#include + +#endif // #ifndef BOOST_SMART_PTR_MAKE_LOCAL_SHARED_HPP_INCLUDED diff --git a/include/boost/smart_ptr/make_local_shared_array.hpp b/include/boost/smart_ptr/make_local_shared_array.hpp new file mode 100644 index 0000000..d0eec2f --- /dev/null +++ b/include/boost/smart_ptr/make_local_shared_array.hpp @@ -0,0 +1,63 @@ +#ifndef BOOST_SMART_PTR_MAKE_LOCAL_SHARED_ARRAY_HPP_INCLUDED +#define BOOST_SMART_PTR_MAKE_LOCAL_SHARED_ARRAY_HPP_INCLUDED + +// make_local_shared_array.hpp +// +// Copyright 2017 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 +// +// See http://www.boost.org/libs/smart_ptr/ for documentation. + +#include +#include +#include +#include + +namespace boost +{ + +namespace detail +{ + +template struct lsp_if_array +{ +}; + +template struct lsp_if_array +{ + typedef boost::local_shared_ptr type; +}; + +template struct lsp_if_array +{ + typedef boost::local_shared_ptr type; +}; + +} // namespace detail + +template typename boost::detail::lsp_if_array::type make_local_shared( Args&&... args ) +{ + return boost::make_shared( std::forward(args)... ); +} + +template typename boost::detail::lsp_if_array::type make_local_shared_noinit( Args&&... args ) +{ + return boost::make_shared_noinit( std::forward(args)... ); +} + +template typename boost::detail::lsp_if_array::type allocate_local_shared( A const & a, Args&&... args ) +{ + return boost::allocate_shared( a, std::forward(args)... ); +} + +template typename boost::detail::lsp_if_array::type allocate_local_shared_noinit( A const & a, Args&&... args ) +{ + return boost::allocate_shared_noinit( a, std::forward(args)... ); +} + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_MAKE_SHARED_OBJECT_HPP_INCLUDED diff --git a/include/boost/smart_ptr/make_local_shared_object.hpp b/include/boost/smart_ptr/make_local_shared_object.hpp new file mode 100644 index 0000000..9605cfe --- /dev/null +++ b/include/boost/smart_ptr/make_local_shared_object.hpp @@ -0,0 +1,63 @@ +#ifndef BOOST_SMART_PTR_MAKE_LOCAL_SHARED_OBJECT_HPP_INCLUDED +#define BOOST_SMART_PTR_MAKE_LOCAL_SHARED_OBJECT_HPP_INCLUDED + +// make_local_shared_object.hpp +// +// Copyright 2017 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 +// +// See http://www.boost.org/libs/smart_ptr/ for documentation. + +#include +#include +#include +#include +#include + +namespace boost +{ + +namespace detail +{ + +template struct lsp_if_not_array +{ + typedef boost::local_shared_ptr type; +}; + +template struct lsp_if_not_array +{ +}; + +template struct lsp_if_not_array +{ +}; + +} // 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)... ); +} + +template typename boost::detail::lsp_if_not_array::type allocate_local_shared_noinit( A const & a ) +{ + return boost::allocate_shared_noinit( a ); +} + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_MAKE_SHARED_OBJECT_HPP_INCLUDED diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 6340cf5..ff33a88 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -223,5 +223,8 @@ import testing ; [ run lsp_array_n_test.cpp ] [ run lsp_array_cv_test.cpp ] [ run lsp_array_cast_test.cpp ] + + [ run make_local_shared_test.cpp ] + [ run make_local_shared_esft_test.cpp ] ; } diff --git a/test/make_local_shared_esft_test.cpp b/test/make_local_shared_esft_test.cpp new file mode 100644 index 0000000..602aaf3 --- /dev/null +++ b/test/make_local_shared_esft_test.cpp @@ -0,0 +1,275 @@ +// make_local_shared_esft_test.cpp +// +// Copyright 2007-2009, 2017 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 + +#if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) || defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) + +int main() +{ +} + +#else + +#include +#include +#include +#include + +class X: public boost::enable_shared_from_this +{ +private: + + X( X const & ); + X & operator=( X const & ); + +public: + + static int instances; + + explicit X( int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0 ) + { + ++instances; + } + + ~X() + { + --instances; + } +}; + +int X::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::make_local_shared< 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 ); + + 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, 2 ); + 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, 2, 3 ); + 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, 2, 3, 4 ); + 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, 2, 3, 4, 5 ); + 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, 2, 3, 4, 5, 6 ); + 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, 2, 3, 4, 5, 6, 7 ); + 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, 2, 3, 4, 5, 6, 7, 8 ); + 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, 2, 3, 4, 5, 6, 7, 8, 9 ); + 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 ); + + return boost::report_errors(); +} + +#endif diff --git a/test/make_local_shared_test.cpp b/test/make_local_shared_test.cpp new file mode 100644 index 0000000..02980a7 --- /dev/null +++ b/test/make_local_shared_test.cpp @@ -0,0 +1,216 @@ +// make_local_shared_test.cpp +// +// Copyright 2007-2009, 2017 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 + +#if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) || defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) + +int main() +{ +} + +#else + +#include +#include +#include +#include +#include + +class X +{ +private: + + X( X const & ); + X & operator=( X const & ); + + void * operator new( std::size_t n ) + { + // lack of this definition causes link errors on Comeau C++ + BOOST_ERROR( "private X::new called" ); + return ::operator new( n ); + } + + void operator delete( void * p ) + { + // lack of this definition causes link errors on MSVC + BOOST_ERROR( "private X::delete called" ); + ::operator delete( p ); + } + +public: + + static int instances; + + int v; + + 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; + } +}; + +int X::instances = 0; + +int main() +{ + { + boost::local_shared_ptr< int > pi = boost::make_local_shared< int >(); + + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( *pi == 0 ); + } + + { + boost::local_shared_ptr< int > pi = boost::make_local_shared< int >( 5 ); + + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( *pi == 5 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::local_shared_ptr< X > pi = boost::make_local_shared< 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::local_shared_ptr< X > pi = boost::make_local_shared< X >( 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::local_shared_ptr< X > pi = boost::make_local_shared< X >( 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::local_shared_ptr< X > pi = boost::make_local_shared< X >( 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::local_shared_ptr< X > pi = boost::make_local_shared< X >( 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::local_shared_ptr< X > pi = boost::make_local_shared< X >( 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::local_shared_ptr< X > pi = boost::make_local_shared< X >( 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::local_shared_ptr< X > pi = boost::make_local_shared< X >( 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::local_shared_ptr< X > pi = boost::make_local_shared< X >( 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::local_shared_ptr< X > pi = boost::make_local_shared< X >( 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(); +} + +#endif From 1f86907a3d50ca084eb05e10739c27510546c048 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 20 Jun 2017 02:00:19 +0300 Subject: [PATCH 05/13] Add more tests --- test/Jamfile.v2 | 2 + test/allocate_local_shared_esft_test.cpp | 276 +++++++++++++++++++++++ test/allocate_local_shared_test.cpp | 235 +++++++++++++++++++ test/make_local_shared_test.cpp | 19 ++ 4 files changed, 532 insertions(+) create mode 100644 test/allocate_local_shared_esft_test.cpp create mode 100644 test/allocate_local_shared_test.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index ff33a88..1c98589 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -226,5 +226,7 @@ import testing ; [ run make_local_shared_test.cpp ] [ run make_local_shared_esft_test.cpp ] + [ run allocate_local_shared_test.cpp ] + [ run allocate_local_shared_esft_test.cpp ] ; } diff --git a/test/allocate_local_shared_esft_test.cpp b/test/allocate_local_shared_esft_test.cpp new file mode 100644 index 0000000..4531434 --- /dev/null +++ b/test/allocate_local_shared_esft_test.cpp @@ -0,0 +1,276 @@ +// allocate_local_shared_esft_test.cpp +// +// Copyright 2007-2009, 2017 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 + +#if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) || defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) + +int main() +{ +} + +#else + +#include +#include +#include +#include +#include + +class X: public boost::enable_shared_from_this +{ +private: + + X( X const & ); + X & operator=( X const & ); + +public: + + static int instances; + + explicit X( int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0, int = 0 ) + { + ++instances; + } + + ~X() + { + --instances; + } +}; + +int X::instances = 0; + +int main() +{ + BOOST_TEST( X::instances == 0 ); + + { + boost::shared_ptr< X > px = boost::allocate_local_shared< 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_local_shared< X >( std::allocator(), 1 ); + 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_local_shared< X >( std::allocator(), 1, 2 ); + 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_local_shared< X >( std::allocator(), 1, 2, 3 ); + 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_local_shared< X >( std::allocator(), 1, 2, 3, 4 ); + 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_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5 ); + 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_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6 ); + 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_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7 ); + 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_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7, 8 ); + 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_local_shared< X >( std::allocator(), 1, 2, 3, 4, 5, 6, 7, 8, 9 ); + 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 ); + + return boost::report_errors(); +} + +#endif diff --git a/test/allocate_local_shared_test.cpp b/test/allocate_local_shared_test.cpp new file mode 100644 index 0000000..fa53dc0 --- /dev/null +++ b/test/allocate_local_shared_test.cpp @@ -0,0 +1,235 @@ +// allocate_local_shared_test.cpp +// +// Copyright 2007-2009, 2017 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 + +#if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) || defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) + +int main() +{ +} + +#else + +#include +#include +#include +#include +#include + +class X +{ +private: + + X( X const & ); + X & operator=( X const & ); + + void * operator new( std::size_t n ) + { + // lack of this definition causes link errors on Comeau C++ + BOOST_ERROR( "private X::new called" ); + return ::operator new( n ); + } + + void operator delete( void * p ) + { + // lack of this definition causes link errors on MSVC + BOOST_ERROR( "private X::delete called" ); + ::operator delete( p ); + } + +public: + + static int instances; + + int v; + + 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; + } +}; + +int X::instances = 0; + +int main() +{ + { + boost::local_shared_ptr< int > pi = boost::allocate_local_shared< int >( std::allocator() ); + + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( *pi == 0 ); + } + + { + boost::local_shared_ptr< int > pi = boost::allocate_local_shared_noinit< int >( std::allocator() ); + + BOOST_TEST( pi.get() != 0 ); + } + + { + boost::local_shared_ptr< int > pi = boost::allocate_local_shared< int >( std::allocator(), 5 ); + + BOOST_TEST( pi.get() != 0 ); + BOOST_TEST( *pi == 5 ); + } + + BOOST_TEST( X::instances == 0 ); + + { + boost::local_shared_ptr< X > pi = boost::allocate_local_shared< 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::local_shared_ptr< X > pi = boost::allocate_local_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::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::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::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::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::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::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::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::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::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::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::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::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::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::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::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::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::local_shared_ptr< X > pi = boost::allocate_local_shared< X >( std::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(); +} + +#endif diff --git a/test/make_local_shared_test.cpp b/test/make_local_shared_test.cpp index 02980a7..c5f7fe3 100644 --- a/test/make_local_shared_test.cpp +++ b/test/make_local_shared_test.cpp @@ -71,6 +71,12 @@ int main() BOOST_TEST( *pi == 0 ); } + { + boost::local_shared_ptr< int > pi = boost::make_local_shared_noinit< int >(); + + BOOST_TEST( pi.get() != 0 ); + } + { boost::local_shared_ptr< int > pi = boost::make_local_shared< int >( 5 ); @@ -93,6 +99,19 @@ int main() BOOST_TEST( X::instances == 0 ); } + { + boost::local_shared_ptr< X > pi = boost::make_local_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::local_shared_ptr< X > pi = boost::make_local_shared< X >( 1 ); boost::weak_ptr wp( pi ); From 2b5869882a4c173e52dd0eee4a4a32919fad84fe Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 20 Jun 2017 04:27:45 +0300 Subject: [PATCH 06/13] Optimize make_local_shared to use a single allocation --- .../smart_ptr/detail/local_counted_base.hpp | 14 +- include/boost/smart_ptr/local_shared_ptr.hpp | 13 +- .../smart_ptr/make_local_shared_object.hpp | 143 ++++++++++++++++-- test/allocate_local_shared_esft_test.cpp | 104 ++++++++----- test/allocate_shared_esft_test.cpp | 22 +++ test/allocate_shared_test.cpp | 19 +++ test/make_local_shared_esft_test.cpp | 22 +++ test/make_shared_esft_test.cpp | 22 +++ test/make_shared_test.cpp | 19 +++ 9 files changed, 316 insertions(+), 62 deletions(-) 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 ); From b104d85d95f8793b7496aded52ba22cbceadf3e9 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 20 Jun 2017 05:36:47 +0300 Subject: [PATCH 07/13] Fix use of allocator_traits --- .../smart_ptr/make_local_shared_object.hpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/boost/smart_ptr/make_local_shared_object.hpp b/include/boost/smart_ptr/make_local_shared_object.hpp index c8a2330..4d76e29 100644 --- a/include/boost/smart_ptr/make_local_shared_object.hpp +++ b/include/boost/smart_ptr/make_local_shared_object.hpp @@ -113,7 +113,16 @@ public: template typename boost::detail::lsp_if_not_array::type allocate_local_shared( A const & a, Args&&... args ) { +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + typedef typename std::allocator_traits::template rebind_alloc A2; + +#else + + typedef typename A::template rebind::other A2; + +#endif + A2 a2( a ); typedef boost::detail::lsp_ms_deleter D; @@ -145,7 +154,16 @@ template typename boost::detail::lsp_if_not_arr template typename boost::detail::lsp_if_not_array::type allocate_local_shared_noinit( A const & a ) { +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + typedef typename std::allocator_traits::template rebind_alloc A2; + +#else + + typedef typename A::template rebind::other A2; + +#endif + A2 a2( a ); typedef boost::detail::lsp_ms_deleter D; From 1c097b57649eb825aa6585000dde60252585daeb Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 20 Jun 2017 17:47:17 +0300 Subject: [PATCH 08/13] Add get_deleter test with an incomplete class --- test/Jamfile.v2 | 2 ++ test/get_deleter_test2.cpp | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 test/get_deleter_test2.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 1c98589..2c95d3b 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -218,6 +218,8 @@ import testing ; [ run atomic_sp_constexpr_test.cpp ] + [ run get_deleter_test2.cpp ] + [ run local_sp_test.cpp ] [ run lsp_array_test.cpp ] [ run lsp_array_n_test.cpp ] diff --git a/test/get_deleter_test2.cpp b/test/get_deleter_test2.cpp new file mode 100644 index 0000000..4ddc65e --- /dev/null +++ b/test/get_deleter_test2.cpp @@ -0,0 +1,37 @@ +// +// get_deleter_test2.cpp +// +// Copyright 2017 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 + +struct deleter; + +struct X +{ +}; + +static void test_get_deleter( boost::shared_ptr const & p ) +{ + BOOST_TEST( boost::get_deleter( p ) != 0 ); +} + +struct deleter +{ + void operator()( X const * p ) { delete p; } +}; + +int main() +{ + boost::shared_ptr p( new X, deleter() ); + + test_get_deleter( p ); + + return boost::report_errors(); +} From 6e5a382b6b84b4ef9d23fefe48bdfcc24acd7305 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 20 Jun 2017 19:01:16 +0300 Subject: [PATCH 09/13] Start work on get_deleter for local_shared_ptr --- .../smart_ptr/detail/local_counted_base.hpp | 1 - .../smart_ptr/detail/local_sp_deleter.hpp | 82 ++++++++++++++++ .../boost/smart_ptr/detail/shared_count.hpp | 5 + .../detail/sp_counted_base_acc_ia64.hpp | 1 + .../smart_ptr/detail/sp_counted_base_aix.hpp | 1 + .../detail/sp_counted_base_clang.hpp | 1 + .../detail/sp_counted_base_cw_ppc.hpp | 1 + .../detail/sp_counted_base_cw_x86.hpp | 1 + .../detail/sp_counted_base_gcc_ia64.hpp | 1 + .../detail/sp_counted_base_gcc_mips.hpp | 1 + .../detail/sp_counted_base_gcc_ppc.hpp | 1 + .../detail/sp_counted_base_gcc_sparc.hpp | 1 + .../detail/sp_counted_base_gcc_x86.hpp | 1 + .../smart_ptr/detail/sp_counted_base_nt.hpp | 1 + .../smart_ptr/detail/sp_counted_base_pt.hpp | 1 + .../detail/sp_counted_base_snc_ps3.hpp | 1 + .../detail/sp_counted_base_solaris.hpp | 1 + .../smart_ptr/detail/sp_counted_base_spin.hpp | 1 + .../detail/sp_counted_base_std_atomic.hpp | 1 + .../smart_ptr/detail/sp_counted_base_sync.hpp | 1 + .../detail/sp_counted_base_vacpp_ppc.hpp | 1 + .../smart_ptr/detail/sp_counted_base_w32.hpp | 1 + .../smart_ptr/detail/sp_counted_impl.hpp | 28 ++++++ include/boost/smart_ptr/local_shared_ptr.hpp | 57 +++-------- .../smart_ptr/make_local_shared_object.hpp | 1 - include/boost/smart_ptr/shared_ptr.hpp | 58 +++++++---- test/Jamfile.v2 | 5 +- test/get_local_deleter_test.cpp | 95 +++++++++++++++++++ test/get_local_deleter_test2.cpp | 43 +++++++++ 29 files changed, 326 insertions(+), 68 deletions(-) create mode 100644 include/boost/smart_ptr/detail/local_sp_deleter.hpp create mode 100644 test/get_local_deleter_test.cpp create mode 100644 test/get_local_deleter_test2.cpp diff --git a/include/boost/smart_ptr/detail/local_counted_base.hpp b/include/boost/smart_ptr/detail/local_counted_base.hpp index f5a5244..b9a3911 100644 --- a/include/boost/smart_ptr/detail/local_counted_base.hpp +++ b/include/boost/smart_ptr/detail/local_counted_base.hpp @@ -17,7 +17,6 @@ // // See http://www.boost.org/libs/smart_ptr/ for documentation. -#include #include #include #include diff --git a/include/boost/smart_ptr/detail/local_sp_deleter.hpp b/include/boost/smart_ptr/detail/local_sp_deleter.hpp new file mode 100644 index 0000000..3dd62fa --- /dev/null +++ b/include/boost/smart_ptr/detail/local_sp_deleter.hpp @@ -0,0 +1,82 @@ +#ifndef BOOST_SMART_PTR_DETAIL_LOCAL_SP_DELETER_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_LOCAL_SP_DELETER_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// detail/local_sp_deleter.hpp +// +// Copyright 2017 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) +// +// See http://www.boost.org/libs/smart_ptr/ for documentation. + +#include +#include + +namespace boost +{ + +namespace detail +{ + +template class local_sp_deleter: public local_counted_impl_em +{ +private: + + D d_; + +public: + + local_sp_deleter(): d_() + { + } + + explicit local_sp_deleter( D const& d ) BOOST_SP_NOEXCEPT: d_( d ) + { + } + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + explicit local_sp_deleter( D&& d ) BOOST_SP_NOEXCEPT: d_( std::move(d) ) + { + } + +#endif + + D& deleter() + { + return d_; + } + + template void operator()( Y* p ) BOOST_SP_NOEXCEPT + { + d_( p ); + } + +#if !defined( BOOST_NO_CXX11_NULLPTR ) + + void operator()( boost::detail::sp_nullptr_t p ) BOOST_SP_NOEXCEPT + { + d_( p ); + } + +#endif +}; + +template D * get_local_deleter( local_sp_deleter * p ) +{ + return &p->deleter(); +} + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_LOCAL_SP_DELETER_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/shared_count.hpp b/include/boost/smart_ptr/detail/shared_count.hpp index 7f375e8..1fc1433 100644 --- a/include/boost/smart_ptr/detail/shared_count.hpp +++ b/include/boost/smart_ptr/detail/shared_count.hpp @@ -496,6 +496,11 @@ public: return pi_? pi_->get_deleter( ti ): 0; } + void * get_local_deleter( sp_typeinfo const & ti ) const + { + return pi_? pi_->get_local_deleter( ti ): 0; + } + void * get_untyped_deleter() const { return pi_? pi_->get_untyped_deleter(): 0; diff --git a/include/boost/smart_ptr/detail/sp_counted_base_acc_ia64.hpp b/include/boost/smart_ptr/detail/sp_counted_base_acc_ia64.hpp index cebc243..ec6f6ee 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_acc_ia64.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_acc_ia64.hpp @@ -104,6 +104,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_aix.hpp b/include/boost/smart_ptr/detail/sp_counted_base_aix.hpp index fe6c727..ce8ee68 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_aix.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_aix.hpp @@ -96,6 +96,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp b/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp index 7598495..8b3bfad 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp @@ -98,6 +98,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_cw_ppc.hpp b/include/boost/smart_ptr/detail/sp_counted_base_cw_ppc.hpp index 6c268e8..065f7c3 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_cw_ppc.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_cw_ppc.hpp @@ -124,6 +124,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_cw_x86.hpp b/include/boost/smart_ptr/detail/sp_counted_base_cw_x86.hpp index 81eba6f..3a3d4d4 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_cw_x86.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_cw_x86.hpp @@ -112,6 +112,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_gcc_ia64.hpp b/include/boost/smart_ptr/detail/sp_counted_base_gcc_ia64.hpp index f6e3904..6c3cce8 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_gcc_ia64.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_gcc_ia64.hpp @@ -111,6 +111,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp b/include/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp index 545c8ae..76ac2a6 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp @@ -135,6 +135,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_gcc_ppc.hpp b/include/boost/smart_ptr/detail/sp_counted_base_gcc_ppc.hpp index 2e5bc0e..0fb8074 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_gcc_ppc.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_gcc_ppc.hpp @@ -135,6 +135,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp b/include/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp index c6d20ce..b8bb707 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp @@ -120,6 +120,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp b/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp index 173dce5..3d2dd61 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp @@ -127,6 +127,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_nt.hpp b/include/boost/smart_ptr/detail/sp_counted_base_nt.hpp index 5c901f9..dea905c 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_nt.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_nt.hpp @@ -59,6 +59,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_pt.hpp b/include/boost/smart_ptr/detail/sp_counted_base_pt.hpp index a16d2d8..85f2563 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_pt.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_pt.hpp @@ -71,6 +71,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_snc_ps3.hpp b/include/boost/smart_ptr/detail/sp_counted_base_snc_ps3.hpp index 56ed79f..7b5f917 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_snc_ps3.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_snc_ps3.hpp @@ -115,6 +115,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_solaris.hpp b/include/boost/smart_ptr/detail/sp_counted_base_solaris.hpp index 0e05fef..0db9c6c 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_solaris.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_solaris.hpp @@ -62,6 +62,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_spin.hpp b/include/boost/smart_ptr/detail/sp_counted_base_spin.hpp index 77734e7..faf503a 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_spin.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_spin.hpp @@ -84,6 +84,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp b/include/boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp index cab8453..7a188f8 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp @@ -90,6 +90,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_sync.hpp b/include/boost/smart_ptr/detail/sp_counted_base_sync.hpp index fafed0e..d2138e7 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_sync.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_sync.hpp @@ -109,6 +109,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_vacpp_ppc.hpp b/include/boost/smart_ptr/detail/sp_counted_base_vacpp_ppc.hpp index 162f309..f2de3b0 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_vacpp_ppc.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_vacpp_ppc.hpp @@ -104,6 +104,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_base_w32.hpp b/include/boost/smart_ptr/detail/sp_counted_base_w32.hpp index 4ba509c..960e42e 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base_w32.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base_w32.hpp @@ -67,6 +67,7 @@ public: } virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_local_deleter( sp_typeinfo const & ti ) = 0; virtual void * get_untyped_deleter() = 0; void add_ref_copy() diff --git a/include/boost/smart_ptr/detail/sp_counted_impl.hpp b/include/boost/smart_ptr/detail/sp_counted_impl.hpp index b29769e..ad5d254 100644 --- a/include/boost/smart_ptr/detail/sp_counted_impl.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_impl.hpp @@ -50,6 +50,19 @@ void sp_scalar_destructor_hook( void * px, std::size_t size, void * pn ); namespace detail { +// get_local_deleter + +template class local_sp_deleter; + +template D * get_local_deleter( D * p ) +{ + return 0; +} + +template D * get_local_deleter( local_sp_deleter * p ); + +// + template class sp_counted_impl_p: public sp_counted_base { private: @@ -83,6 +96,11 @@ public: return 0; } + virtual void * get_local_deleter( sp_typeinfo const & ) + { + return 0; + } + virtual void * get_untyped_deleter() { return 0; @@ -158,6 +176,11 @@ public: return ti == BOOST_SP_TYPEID(D)? &reinterpret_cast( del ): 0; } + virtual void * get_local_deleter( sp_typeinfo const & ti ) + { + return ti == BOOST_SP_TYPEID(D)? boost::detail::get_local_deleter( &reinterpret_cast( del ) ): 0; + } + virtual void * get_untyped_deleter() { return &reinterpret_cast( del ); @@ -246,6 +269,11 @@ public: return ti == BOOST_SP_TYPEID( D )? &reinterpret_cast( d_ ): 0; } + virtual void * get_local_deleter( sp_typeinfo const & ti ) + { + return ti == BOOST_SP_TYPEID(D)? boost::detail::get_local_deleter( &reinterpret_cast( d_ ) ): 0; + } + virtual void * get_untyped_deleter() { return &reinterpret_cast( d_ ); diff --git a/include/boost/smart_ptr/local_shared_ptr.hpp b/include/boost/smart_ptr/local_shared_ptr.hpp index d7a1278..2c0d2ab 100644 --- a/include/boost/smart_ptr/local_shared_ptr.hpp +++ b/include/boost/smart_ptr/local_shared_ptr.hpp @@ -11,7 +11,6 @@ // // See http://www.boost.org/libs/smart_ptr/ for documentation. -#include #include namespace boost @@ -22,46 +21,7 @@ template class local_shared_ptr; namespace detail { -template class local_sp_deleter: public local_counted_impl_em -{ -private: - - D d_; - -public: - - local_sp_deleter(): d_() - { - } - - explicit local_sp_deleter( D const& d ) BOOST_SP_NOEXCEPT: d_( d ) - { - } - -#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) - - explicit local_sp_deleter( D&& d ) BOOST_SP_NOEXCEPT: d_( std::move(d) ) - { - } - -#endif - - template void operator()( Y* p ) BOOST_SP_NOEXCEPT - { - d_( p ); - } - -#if !defined( BOOST_NO_CXX11_NULLPTR ) - - void operator()( boost::detail::sp_nullptr_t p ) BOOST_SP_NOEXCEPT - { - d_( p ); - } - -#endif -}; - -template< class E, class Y > inline void lsp_pointer_construct( boost::local_shared_ptr< E > * ppx, Y * p, boost::detail::local_counted_base * & pn ) +template< class E, class Y > inline void lsp_pointer_construct( boost::local_shared_ptr< E > * /*ppx*/, Y * p, boost::detail::local_counted_base * & pn ) { boost::detail::sp_assert_convertible< Y, E >(); @@ -76,7 +36,7 @@ template< class E, class Y > inline void lsp_pointer_construct( boost::local_sha pn = pd; } -template< class E, class Y > inline void lsp_pointer_construct( boost::local_shared_ptr< E[] > * ppx, Y * p, boost::detail::local_counted_base * & pn ) +template< class E, class Y > inline void lsp_pointer_construct( boost::local_shared_ptr< E[] > * /*ppx*/, Y * p, boost::detail::local_counted_base * & pn ) { boost::detail::sp_assert_convertible< Y[], E[] >(); @@ -91,7 +51,7 @@ template< class E, class Y > inline void lsp_pointer_construct( boost::local_sha pn = pd; } -template< class E, std::size_t N, class Y > inline void lsp_pointer_construct( boost::local_shared_ptr< E[N] > * ppx, Y * p, boost::detail::local_counted_base * & pn ) +template< class E, std::size_t N, class Y > inline void lsp_pointer_construct( boost::local_shared_ptr< E[N] > * /*ppx*/, Y * p, boost::detail::local_counted_base * & pn ) { boost::detail::sp_assert_convertible< Y[N], E[N] >(); @@ -106,7 +66,7 @@ template< class E, std::size_t N, class Y > inline void lsp_pointer_construct( b pn = pd; } -template< class E, class P, class D > inline void lsp_deleter_construct( boost::local_shared_ptr< E > * ppx, P p, D const& d, boost::detail::local_counted_base * & pn ) +template< class E, class P, class D > inline void lsp_deleter_construct( boost::local_shared_ptr< E > * /*ppx*/, P p, D const& d, boost::detail::local_counted_base * & pn ) { typedef boost::detail::local_sp_deleter D2; @@ -119,7 +79,7 @@ template< class E, class P, class D > inline void lsp_deleter_construct( boost:: pn = pd; } -template< class E, class P, class D, class A > inline void lsp_allocator_construct( boost::local_shared_ptr< E > * ppx, P p, D const& d, A const& a, boost::detail::local_counted_base * & pn ) +template< class E, class P, class D, class A > inline void lsp_allocator_construct( boost::local_shared_ptr< E > * /*ppx*/, P p, D const& d, A const& a, boost::detail::local_counted_base * & pn ) { typedef boost::detail::local_sp_deleter D2; @@ -702,6 +662,13 @@ template std::basic_ostream & operator<< ( std: #endif // !defined(BOOST_NO_IOSTREAM) +// get_deleter + +template D * get_deleter( local_shared_ptr const & p ) BOOST_SP_NOEXCEPT +{ + return get_deleter( shared_ptr( p ) ); +} + // hash_value template< class T > struct hash; diff --git a/include/boost/smart_ptr/make_local_shared_object.hpp b/include/boost/smart_ptr/make_local_shared_object.hpp index 4d76e29..46426b5 100644 --- a/include/boost/smart_ptr/make_local_shared_object.hpp +++ b/include/boost/smart_ptr/make_local_shared_object.hpp @@ -12,7 +12,6 @@ // See http://www.boost.org/libs/smart_ptr/ for documentation. #include -#include #include #include #include diff --git a/include/boost/smart_ptr/shared_ptr.hpp b/include/boost/smart_ptr/shared_ptr.hpp index c87901a..a735062 100644 --- a/include/boost/smart_ptr/shared_ptr.hpp +++ b/include/boost/smart_ptr/shared_ptr.hpp @@ -766,6 +766,11 @@ public: return pn.get_deleter( ti ); } + void * _internal_get_local_deleter( boost::detail::sp_typeinfo const & ti ) const BOOST_SP_NOEXCEPT + { + return pn.get_local_deleter( ti ); + } + void * _internal_get_untyped_deleter() const BOOST_SP_NOEXCEPT { return pn.get_untyped_deleter(); @@ -980,27 +985,13 @@ template std::basic_ostream & operator<< (std:: namespace detail { -#if ( defined(__GNUC__) && BOOST_WORKAROUND(__GNUC__, < 3) ) || \ - ( defined(__EDG_VERSION__) && BOOST_WORKAROUND(__EDG_VERSION__, <= 238) ) || \ - ( defined(__HP_aCC) && BOOST_WORKAROUND(__HP_aCC, <= 33500) ) - -// g++ 2.9x doesn't allow static_cast(void *) -// apparently EDG 2.38 and HP aCC A.03.35 also don't accept it - -template D * basic_get_deleter(shared_ptr const & p) -{ - void const * q = p._internal_get_deleter(BOOST_SP_TYPEID(D)); - return const_cast(static_cast(q)); -} - -#else - template D * basic_get_deleter( shared_ptr const & p ) BOOST_SP_NOEXCEPT { return static_cast( p._internal_get_deleter(BOOST_SP_TYPEID(D)) ); } -#endif +template D * basic_get_local_deleter( D *, shared_ptr const & p ) BOOST_SP_NOEXCEPT; +template D const * basic_get_local_deleter( D const *, shared_ptr const & p ) BOOST_SP_NOEXCEPT; class esft2_deleter_wrapper { @@ -1035,17 +1026,22 @@ public: template D * get_deleter( shared_ptr const & p ) BOOST_SP_NOEXCEPT { - D *del = boost::detail::basic_get_deleter(p); + D * d = boost::detail::basic_get_deleter( p ); - if(del == 0) + if( d == 0 ) + { + d = boost::detail::basic_get_local_deleter( d, p ); + } + + if( d == 0 ) { boost::detail::esft2_deleter_wrapper *del_wrapper = boost::detail::basic_get_deleter(p); // The following get_deleter method call is fully qualified because // older versions of gcc (2.95, 3.2.3) fail to compile it when written del_wrapper->get_deleter() - if(del_wrapper) del = del_wrapper->::boost::detail::esft2_deleter_wrapper::get_deleter(); + if(del_wrapper) d = del_wrapper->::boost::detail::esft2_deleter_wrapper::get_deleter(); } - return del; + return d; } // atomic access @@ -1138,6 +1134,28 @@ template< class T > std::size_t hash_value( boost::shared_ptr const & p ) BOO } // namespace boost +#include + +namespace boost +{ + +namespace detail +{ + +template D * basic_get_local_deleter( D *, shared_ptr const & p ) BOOST_SP_NOEXCEPT +{ + return static_cast( p._internal_get_local_deleter( BOOST_SP_TYPEID(local_sp_deleter) ) ); +} + +template D const * basic_get_local_deleter( D const *, shared_ptr const & p ) BOOST_SP_NOEXCEPT +{ + return static_cast( p._internal_get_local_deleter( BOOST_SP_TYPEID(local_sp_deleter) ) ); +} + +} // namespace detail + +} // namespace boost + #if defined( BOOST_SP_DISABLE_DEPRECATED ) #pragma GCC diagnostic pop #endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 2c95d3b..89da83e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -225,7 +225,10 @@ import testing ; [ run lsp_array_n_test.cpp ] [ run lsp_array_cv_test.cpp ] [ run lsp_array_cast_test.cpp ] - + + [ run get_local_deleter_test.cpp ] + [ run get_local_deleter_test2.cpp ] + [ run make_local_shared_test.cpp ] [ run make_local_shared_esft_test.cpp ] [ run allocate_local_shared_test.cpp ] diff --git a/test/get_local_deleter_test.cpp b/test/get_local_deleter_test.cpp new file mode 100644 index 0000000..8c45af7 --- /dev/null +++ b/test/get_local_deleter_test.cpp @@ -0,0 +1,95 @@ +// +// get_local_deleter_test.cpp +// +// Copyright 2002, 2017 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 + +struct deleter +{ + int data; + + deleter(): data(0) + { + } + + void operator()(void *) + { + BOOST_TEST(data == 17041); + } +}; + +struct deleter2 +{ +}; + +struct X +{ +}; + +int main() +{ + { + boost::local_shared_ptr p; + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + boost::local_shared_ptr p(new X); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + X x; + boost::local_shared_ptr p(&x, deleter()); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + + deleter * q = boost::get_deleter(p); + + BOOST_TEST(q != 0); + BOOST_TEST(q->data == 0); + + q->data = 17041; + + deleter const * r = boost::get_deleter(p); + + BOOST_TEST(r == q); + BOOST_TEST(r->data == 17041); + } + + return boost::report_errors(); +} diff --git a/test/get_local_deleter_test2.cpp b/test/get_local_deleter_test2.cpp new file mode 100644 index 0000000..a0023a9 --- /dev/null +++ b/test/get_local_deleter_test2.cpp @@ -0,0 +1,43 @@ +// +// get_local_deleter_test2.cpp +// +// Copyright 2017 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 + +struct deleter; + +struct X +{ +}; + +static void test_lsp_get_deleter( boost::local_shared_ptr const & p ) +{ + BOOST_TEST( boost::get_deleter( p ) != 0 ); +} + +static void test_sp_get_deleter( boost::shared_ptr const & p ) +{ + BOOST_TEST( boost::get_deleter( p ) != 0 ); +} + +struct deleter +{ + void operator()( X const * p ) { delete p; } +}; + +int main() +{ + boost::local_shared_ptr p( new X, deleter() ); + + test_lsp_get_deleter( p ); + test_sp_get_deleter( p ); + + return boost::report_errors(); +} From fb17bf685e3633b070a3ce3638ee74372f39aeb3 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 20 Jun 2017 20:38:26 +0300 Subject: [PATCH 10/13] Add more tests; fix errors --- .../boost/smart_ptr/allocate_shared_array.hpp | 16 ++ .../smart_ptr/detail/local_sp_deleter.hpp | 11 +- .../smart_ptr/detail/sp_counted_impl.hpp | 7 +- .../smart_ptr/make_local_shared_array.hpp | 4 +- test/Jamfile.v2 | 3 + test/get_local_deleter_array_test.cpp | 151 ++++++++++++++++++ test/get_local_deleter_array_test2.cpp | 74 +++++++++ test/get_local_deleter_test3.cpp | 59 +++++++ test/local_sp_test.cpp | 4 +- 9 files changed, 321 insertions(+), 8 deletions(-) create mode 100644 test/get_local_deleter_array_test.cpp create mode 100644 test/get_local_deleter_array_test2.cpp create mode 100644 test/get_local_deleter_test3.cpp diff --git a/include/boost/smart_ptr/allocate_shared_array.hpp b/include/boost/smart_ptr/allocate_shared_array.hpp index b9c4ce4..39b7567 100644 --- a/include/boost/smart_ptr/allocate_shared_array.hpp +++ b/include/boost/smart_ptr/allocate_shared_array.hpp @@ -766,6 +766,10 @@ public: return ti == BOOST_SP_TYPEID(deleter_type)? &reinterpret_cast(deleter_): 0; } + void* get_local_deleter(const sp_typeinfo&) { + return 0; + } + void* get_untyped_deleter() { return &reinterpret_cast(deleter_); } @@ -807,6 +811,10 @@ public: return ti == BOOST_SP_TYPEID(deleter_type)? &reinterpret_cast(deleter_): 0; } + void* get_local_deleter(const sp_typeinfo&) { + return 0; + } + void* get_untyped_deleter() { return &reinterpret_cast(deleter_); } @@ -853,6 +861,10 @@ public: return ti == BOOST_SP_TYPEID(deleter_type)? &reinterpret_cast(deleter_): 0; } + void* get_local_deleter(const sp_typeinfo&) { + return 0; + } + void* get_untyped_deleter() { return &reinterpret_cast(deleter_); } @@ -898,6 +910,10 @@ public: return ti == BOOST_SP_TYPEID(deleter_type)? &reinterpret_cast(deleter_): 0; } + void* get_local_deleter(const sp_typeinfo&) { + return 0; + } + void* get_untyped_deleter() { return &reinterpret_cast(deleter_); } diff --git a/include/boost/smart_ptr/detail/local_sp_deleter.hpp b/include/boost/smart_ptr/detail/local_sp_deleter.hpp index 3dd62fa..7d04f1d 100644 --- a/include/boost/smart_ptr/detail/local_sp_deleter.hpp +++ b/include/boost/smart_ptr/detail/local_sp_deleter.hpp @@ -70,9 +70,18 @@ public: #endif }; +template<> class local_sp_deleter +{ +}; + template D * get_local_deleter( local_sp_deleter * p ) { - return &p->deleter(); + return &p->deleter(); +} + +inline void * get_local_deleter( local_sp_deleter * /*p*/ ) +{ + return 0; } } // namespace detail diff --git a/include/boost/smart_ptr/detail/sp_counted_impl.hpp b/include/boost/smart_ptr/detail/sp_counted_impl.hpp index ad5d254..fa2f75e 100644 --- a/include/boost/smart_ptr/detail/sp_counted_impl.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_impl.hpp @@ -26,6 +26,7 @@ #include #include +#include #if defined(BOOST_SP_USE_QUICK_ALLOCATOR) #include @@ -54,7 +55,7 @@ namespace detail template class local_sp_deleter; -template D * get_local_deleter( D * p ) +template D * get_local_deleter( D * /*p*/ ) { return 0; } @@ -178,7 +179,7 @@ public: virtual void * get_local_deleter( sp_typeinfo const & ti ) { - return ti == BOOST_SP_TYPEID(D)? boost::detail::get_local_deleter( &reinterpret_cast( del ) ): 0; + return ti == BOOST_SP_TYPEID(D)? boost::detail::get_local_deleter( boost::addressof( del ) ): 0; } virtual void * get_untyped_deleter() @@ -271,7 +272,7 @@ public: virtual void * get_local_deleter( sp_typeinfo const & ti ) { - return ti == BOOST_SP_TYPEID(D)? boost::detail::get_local_deleter( &reinterpret_cast( d_ ) ): 0; + return ti == BOOST_SP_TYPEID(D)? boost::detail::get_local_deleter( boost::addressof( d_ ) ): 0; } virtual void * get_untyped_deleter() diff --git a/include/boost/smart_ptr/make_local_shared_array.hpp b/include/boost/smart_ptr/make_local_shared_array.hpp index d0eec2f..136c767 100644 --- a/include/boost/smart_ptr/make_local_shared_array.hpp +++ b/include/boost/smart_ptr/make_local_shared_array.hpp @@ -28,12 +28,12 @@ template struct lsp_if_array template struct lsp_if_array { - typedef boost::local_shared_ptr type; + typedef boost::local_shared_ptr type; }; template struct lsp_if_array { - typedef boost::local_shared_ptr type; + typedef boost::local_shared_ptr type; }; } // namespace detail diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index d963dda..10b14cf 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -231,6 +231,9 @@ import testing ; [ run get_local_deleter_test.cpp ] [ run get_local_deleter_test2.cpp ] + [ run get_local_deleter_test3.cpp ] + [ run get_local_deleter_array_test.cpp ] + [ run get_local_deleter_array_test2.cpp ] [ run make_local_shared_test.cpp ] [ run make_local_shared_esft_test.cpp ] diff --git a/test/get_local_deleter_array_test.cpp b/test/get_local_deleter_array_test.cpp new file mode 100644 index 0000000..3a8351b --- /dev/null +++ b/test/get_local_deleter_array_test.cpp @@ -0,0 +1,151 @@ +// +// get_local_deleter_array_test2.cpp +// +// Copyright 2002, 2011, 2017 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 + +struct deleter +{ + int data; + + deleter(): data(0) + { + } + + void operator()(void *) + { + BOOST_TEST(data == 17041); + } +}; + +struct deleter2 +{ +}; + +struct X +{ +}; + +int main() +{ + { + boost::local_shared_ptr p; + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + boost::local_shared_ptr p; + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + boost::local_shared_ptr p(new X[1]); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + boost::local_shared_ptr p(new X[1]); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + X x[1]; + boost::local_shared_ptr p(x, deleter()); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + + deleter * q = boost::get_deleter(p); + + BOOST_TEST(q != 0); + BOOST_TEST(q->data == 0); + + q->data = 17041; + + deleter const * r = boost::get_deleter(p); + + BOOST_TEST(r == q); + BOOST_TEST(r->data == 17041); + } + + { + X x[1]; + boost::local_shared_ptr p(x, deleter()); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + + deleter * q = boost::get_deleter(p); + + BOOST_TEST(q != 0); + BOOST_TEST(q->data == 0); + + q->data = 17041; + + deleter const * r = boost::get_deleter(p); + + BOOST_TEST(r == q); + BOOST_TEST(r->data == 17041); + } + + return boost::report_errors(); +} diff --git a/test/get_local_deleter_array_test2.cpp b/test/get_local_deleter_array_test2.cpp new file mode 100644 index 0000000..999fffe --- /dev/null +++ b/test/get_local_deleter_array_test2.cpp @@ -0,0 +1,74 @@ +// +// get_local_deleter_test2.cpp +// +// Copyright 2002, 2017 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 + +#if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) || defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) + +int main() +{ +} + +#else + +#include +#include +#include + +struct deleter +{ +}; + +struct deleter2; + +struct X +{ +}; + +int main() +{ + { + boost::local_shared_ptr p = boost::make_local_shared( 1 ); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + { + boost::local_shared_ptr p = boost::make_local_shared(); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + return boost::report_errors(); +} + +struct deleter2 +{ +}; + +#endif diff --git a/test/get_local_deleter_test3.cpp b/test/get_local_deleter_test3.cpp new file mode 100644 index 0000000..655c7fc --- /dev/null +++ b/test/get_local_deleter_test3.cpp @@ -0,0 +1,59 @@ +// +// get_local_deleter_test3.cpp +// +// Copyright 2002, 2017 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 + +#if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) || defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) + +int main() +{ +} + +#else + +#include +#include +#include + +struct deleter +{ +}; + +struct deleter2; + +struct X +{ +}; + +int main() +{ + { + boost::local_shared_ptr p = boost::make_local_shared(); + + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + BOOST_TEST(boost::get_deleter(p) == 0); + } + + return boost::report_errors(); +} + +struct deleter2 +{ +}; + +#endif diff --git a/test/local_sp_test.cpp b/test/local_sp_test.cpp index dd161d8..dc0e316 100644 --- a/test/local_sp_test.cpp +++ b/test/local_sp_test.cpp @@ -1929,7 +1929,7 @@ template static void test_deleter_reset( boost::local_shared_p boost::shared_ptr p3( p2 ); - // BOOST_TEST( boost::get_deleter< deleter >( p3 ) != 0 ); + BOOST_TEST( boost::get_deleter< deleter >( p3 ) != 0 ); p3.reset(); BOOST_TEST( !called ); @@ -2010,7 +2010,7 @@ template static void test_allocator_reset( boost::local_shared boost::shared_ptr p3( p2 ); - // BOOST_TEST( boost::get_deleter< deleter >( p3 ) != 0 ); + BOOST_TEST( boost::get_deleter< deleter >( p3 ) != 0 ); p3.reset(); BOOST_TEST( !called ); From f901988e57137f05afac20e2985d366144131192 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 20 Jun 2017 21:38:03 +0300 Subject: [PATCH 11/13] Store shared_count in local_counted_base, not shared_ptr --- .../smart_ptr/detail/local_counted_base.hpp | 21 ++++++++++--------- include/boost/smart_ptr/local_shared_ptr.hpp | 21 ++++++++++--------- .../smart_ptr/make_local_shared_object.hpp | 4 ++-- include/boost/smart_ptr/shared_ptr.hpp | 21 +++++++++++++++++++ 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/include/boost/smart_ptr/detail/local_counted_base.hpp b/include/boost/smart_ptr/detail/local_counted_base.hpp index b9a3911..2e5f6ae 100644 --- a/include/boost/smart_ptr/detail/local_counted_base.hpp +++ b/include/boost/smart_ptr/detail/local_counted_base.hpp @@ -17,6 +17,7 @@ // // See http://www.boost.org/libs/smart_ptr/ for documentation. +#include #include #include #include @@ -56,7 +57,7 @@ public: virtual void local_cb_destroy() BOOST_SP_NOEXCEPT = 0; - virtual boost::shared_ptr local_cb_get_shared_ptr() const BOOST_SP_NOEXCEPT = 0; + virtual boost::detail::shared_count local_cb_get_shared_count() const BOOST_SP_NOEXCEPT = 0; void add_ref() BOOST_SP_NOEXCEPT { @@ -95,17 +96,17 @@ private: private: - boost::shared_ptr pn_; + shared_count pn_; public: - template explicit local_counted_impl( boost::shared_ptr const& pn ): pn_( pn ) + explicit local_counted_impl( shared_count const& pn ): pn_( pn ) { } #if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) - template explicit local_counted_impl( boost::shared_ptr&& pn ): pn_( std::move(pn) ) + explicit local_counted_impl( shared_count && pn ): pn_( std::move(pn) ) { } @@ -116,9 +117,9 @@ public: delete this; } - virtual boost::shared_ptr local_cb_get_shared_ptr() const BOOST_SP_NOEXCEPT + virtual boost::detail::shared_count local_cb_get_shared_count() const BOOST_SP_NOEXCEPT { - return const_pointer_cast( pn_ ); + return pn_; } }; @@ -126,16 +127,16 @@ class local_counted_impl_em: public local_counted_base { public: - boost::shared_ptr pn_; + shared_count pn_; virtual void local_cb_destroy() BOOST_SP_NOEXCEPT { - pn_.reset(); + shared_count().swap( pn_ ); } - virtual boost::shared_ptr local_cb_get_shared_ptr() const BOOST_SP_NOEXCEPT + virtual boost::detail::shared_count local_cb_get_shared_count() const BOOST_SP_NOEXCEPT { - return const_pointer_cast( pn_ ); + return pn_; } }; diff --git a/include/boost/smart_ptr/local_shared_ptr.hpp b/include/boost/smart_ptr/local_shared_ptr.hpp index 2c0d2ab..2e3b8bf 100644 --- a/include/boost/smart_ptr/local_shared_ptr.hpp +++ b/include/boost/smart_ptr/local_shared_ptr.hpp @@ -31,7 +31,7 @@ template< class E, class Y > inline void lsp_pointer_construct( boost::local_sha D * pd = static_cast< D * >( p2._internal_get_untyped_deleter() ); - pd->pn_ = p2; + pd->pn_ = p2._internal_count(); pn = pd; } @@ -46,7 +46,7 @@ template< class E, class Y > inline void lsp_pointer_construct( boost::local_sha D * pd = static_cast< D * >( p2._internal_get_untyped_deleter() ); - pd->pn_ = p2; + pd->pn_ = p2._internal_count(); pn = pd; } @@ -61,7 +61,7 @@ template< class E, std::size_t N, class Y > inline void lsp_pointer_construct( b D * pd = static_cast< D * >( p2._internal_get_untyped_deleter() ); - pd->pn_ = p2; + pd->pn_ = p2._internal_count(); pn = pd; } @@ -74,7 +74,7 @@ template< class E, class P, class D > inline void lsp_deleter_construct( boost:: D2 * pd = static_cast< D2 * >( p2._internal_get_untyped_deleter() ); - pd->pn_ = p2; + pd->pn_ = p2._internal_count(); pn = pd; } @@ -87,7 +87,7 @@ template< class E, class P, class D, class A > inline void lsp_allocator_constru D2 * pd = static_cast< D2 * >( p2._internal_get_untyped_deleter() ); - pd->pn_ = p2; + pd->pn_ = p2._internal_count(); pn = pd; } @@ -197,7 +197,7 @@ public: if( r.use_count() != 0 ) { - pn = new boost::detail::local_counted_impl( r ); + pn = new boost::detail::local_counted_impl( r._internal_count() ); } } @@ -211,7 +211,8 @@ public: if( r.use_count() != 0 ) { - pn = new boost::detail::local_counted_impl( std::move(r) ); + pn = new boost::detail::local_counted_impl( r._internal_count() ); + r.reset(); } } @@ -230,7 +231,7 @@ public: if( px ) { - pn = new boost::detail::local_counted_impl( shared_ptr( std::move(r) ) ); + pn = new boost::detail::local_counted_impl( shared_ptr( std::move(r) )._internal_count() ); } } @@ -453,7 +454,7 @@ public: if( pn ) { - return static_pointer_cast( pn->local_cb_get_shared_ptr() ); + return shared_ptr( boost::detail::sp_internal_constructor_tag(), px, pn->local_cb_get_shared_count() ); } else { @@ -471,7 +472,7 @@ public: if( pn ) { - return static_pointer_cast( pn->local_cb_get_shared_ptr() ); + return shared_ptr( boost::detail::sp_internal_constructor_tag(), px, pn->local_cb_get_shared_count() ); } else { diff --git a/include/boost/smart_ptr/make_local_shared_object.hpp b/include/boost/smart_ptr/make_local_shared_object.hpp index 46426b5..518c24d 100644 --- a/include/boost/smart_ptr/make_local_shared_object.hpp +++ b/include/boost/smart_ptr/make_local_shared_object.hpp @@ -146,7 +146,7 @@ template typename boost::detail::lsp_if_not_arr T * pt2 = static_cast< T* >( pv ); boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); - pd->pn_ = boost::shared_ptr( pt, pt2 ); + pd->pn_ = pt._internal_count(); return boost::local_shared_ptr( boost::detail::lsp_internal_constructor_tag(), pt2, pd ); } @@ -179,7 +179,7 @@ template typename boost::detail::lsp_if_not_array::type all T * pt2 = static_cast< T* >( pv ); boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); - pd->pn_ = boost::shared_ptr( pt, pt2 ); + pd->pn_ = pt._internal_count(); return boost::local_shared_ptr( boost::detail::lsp_internal_constructor_tag(), pt2, pd ); } diff --git a/include/boost/smart_ptr/shared_ptr.hpp b/include/boost/smart_ptr/shared_ptr.hpp index a735062..e8a302c 100644 --- a/include/boost/smart_ptr/shared_ptr.hpp +++ b/include/boost/smart_ptr/shared_ptr.hpp @@ -323,6 +323,10 @@ template< class T, std::size_t N, class Y > inline void sp_deleter_construct( bo #endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) +struct sp_internal_constructor_tag +{ +}; + } // namespace detail @@ -355,6 +359,18 @@ public: { } +#endif + + BOOST_CONSTEXPR shared_ptr( boost::detail::sp_internal_constructor_tag, element_type * px_, boost::detail::shared_count const & pn_ ) BOOST_SP_NOEXCEPT : px( px_ ), pn( pn_ ) + { + } + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + BOOST_CONSTEXPR shared_ptr( boost::detail::sp_internal_constructor_tag, element_type * px_, boost::detail::shared_count && pn_ ) BOOST_SP_NOEXCEPT : px( px_ ), pn( std::move( pn_ ) ) + { + } + #endif template @@ -781,6 +797,11 @@ public: return px == r.px && pn == r.pn; } + boost::detail::shared_count _internal_count() const BOOST_NOEXCEPT + { + return pn; + } + // Tasteless as this may seem, making all members public allows member templates // to work in the absence of member template friends. (Matthew Langston) From 4e5d067ba8c24710703314027482ed3826b910f7 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 20 Jun 2017 22:26:07 +0300 Subject: [PATCH 12/13] Add local_sp_fn_test --- test/Jamfile.v2 | 2 ++ test/local_sp_fn_test.cpp | 43 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 test/local_sp_fn_test.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 879a1b2..134642d 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -241,5 +241,7 @@ import testing ; [ run make_local_shared_esft_test.cpp ] [ run allocate_local_shared_test.cpp ] [ run allocate_local_shared_esft_test.cpp ] + + [ run local_sp_fn_test.cpp ] ; } diff --git a/test/local_sp_fn_test.cpp b/test/local_sp_fn_test.cpp new file mode 100644 index 0000000..f2a355a --- /dev/null +++ b/test/local_sp_fn_test.cpp @@ -0,0 +1,43 @@ +// +// local_sp_fn_test.cpp +// +// Copyright 2017 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 + +static void f() +{ +} + +struct null_deleter +{ + template void operator()( Y* ) {} +}; + +int main() +{ + boost::local_shared_ptr pf( f, null_deleter() ); + + BOOST_TEST( pf.get() == f ); + BOOST_TEST_EQ( pf.local_use_count(), 1 ); + BOOST_TEST( boost::get_deleter( pf ) != 0 ); + + boost::weak_ptr wp( pf ); + + BOOST_TEST( wp.lock().get() == f ); + BOOST_TEST_EQ( wp.use_count(), 1 ); + + pf.reset(); + + BOOST_TEST( wp.lock().get() == 0 ); + BOOST_TEST_EQ( wp.use_count(), 0 ); + + return boost::report_errors(); +} From e210c5728d30b5b2f9453e8246c59eaa2b676625 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 21 Jun 2017 03:02:48 +0300 Subject: [PATCH 13/13] Add local_shared_ptr.adoc --- doc/smart_ptr.adoc | 2 + doc/smart_ptr/introduction.adoc | 5 +- doc/smart_ptr/local_shared_ptr.adoc | 719 ++++++++++++++++++++++++++++ 3 files changed, 724 insertions(+), 2 deletions(-) create mode 100644 doc/smart_ptr/local_shared_ptr.adoc diff --git a/doc/smart_ptr.adoc b/doc/smart_ptr.adoc index d3210d7..3c299c3 100644 --- a/doc/smart_ptr.adoc +++ b/doc/smart_ptr.adoc @@ -37,6 +37,8 @@ include::smart_ptr/intrusive_ptr.adoc[] include::smart_ptr/intrusive_ref_counter.adoc[] +include::smart_ptr/local_shared_ptr.adoc[] + include::smart_ptr/pointer_cast.adoc[] include::smart_ptr/pointer_to_other.adoc[] diff --git a/doc/smart_ptr/introduction.adoc b/doc/smart_ptr/introduction.adoc index 2154014..ff51823 100644 --- a/doc/smart_ptr/introduction.adoc +++ b/doc/smart_ptr/introduction.adoc @@ -24,13 +24,14 @@ deletion of the object when it is no longer needed. As such, they are examples o acquisition is initialization" idiom described in Bjarne Stroustrup's "The C++ Programming Language", 3rd edition, Section 14.4, Resource Management. -This library provides five smart pointer class templates: +This library provides six smart pointer class templates: * `<>`, used to contain ownership of a dynamically allocated object to the current scope; * `<>`, which provides scoped ownership for a dynamically allocated array; * `<>`, a versatile tool for managing shared ownership of an object or array; * `<>`, a non-owning observer to a shared_ptr-managed object that can be promoted temporarily to shared_ptr; -* `<>`, a pointer to objects with an embedded reference count. +* `<>`, a pointer to objects with an embedded reference count; +* `<>`, providing shared ownership within a single thread. `shared_ptr` and `weak_ptr` are part of the {cpp} standard since its 2011 iteration. diff --git a/doc/smart_ptr/local_shared_ptr.adoc b/doc/smart_ptr/local_shared_ptr.adoc new file mode 100644 index 0000000..d7d34dd --- /dev/null +++ b/doc/smart_ptr/local_shared_ptr.adoc @@ -0,0 +1,719 @@ +//// +Copyright 2017 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 +//// + +[#local_shared_ptr] +# local_shared_ptr: Shared Ownership within a Single Thread +:toc: +:toc-title: +:idprefix: local_shared_ptr_ + +## Description + +`local_shared_ptr` is nearly identical to `shared_ptr`, with the only difference of note being that its reference count is +updated with non-atomic operations. As such, a `local_shared_ptr` and all its copies must reside in (be local to) a single +thread (hence the name.) + +`local_shared_ptr` can be converted to `shared_ptr` and vice versa. Creating a `local_shared_ptr` from a `shared_ptr` creates +a new local reference count; this means that two `local_shared_ptr` instances, both created from the same `shared_ptr`, refer +to the same object but don't share the same count, and as such, can safely be used by two different threads. + +.Two local_shared_ptr instances created from a shared_ptr +``` +shared_ptr p1( new X ); + +local_shared_ptr p2( p1 ); // p2.local_use_count() == 1 +local_shared_ptr p3( p1 ); // p3.local_use_count() also 1 +``` + +Creating the second `local_shared_ptr` from the first one, however, does lead to the two sharing the same count: + +.A local_shared_ptr created from another local_shared_ptr +``` +shared_ptr p1( new X ); + +local_shared_ptr p2( p1 ); // p2.local_use_count() == 1 +local_shared_ptr p3( p2 ); // p3.local_use_count() == 2 +``` + +Two `shared_ptr` instances created from the same `local_shared_ptr` do share ownership: + +.Two shared_ptr instances created from a local_shared_ptr +``` +local_shared_ptr p1( new X ); + +shared_ptr p2( p1 ); // p2.use_count() == 2 +shared_ptr p3( p1 ); // p3.use_count() == 3 +``` + +Here `p2.use_count()` is 2, because `p1` holds a reference, too. + +One can think of `local_shared_ptr` as `shared_ptr>`, with the outer `shared_ptr` using non-atomic operations for +its count. Converting from `local_shared_ptr` to `shared_ptr` gives you a copy of the inner `shared_ptr`; converting from `shared_ptr` +wraps it into an outer `shared_ptr` with a non-atomic use count (conceptually speaking) and returns the result. + +## Synopsis + +`local_shared_ptr` is defined in ``. + +``` +namespace boost { + + template class local_shared_ptr { + public: + + typedef /*see below*/ element_type; + + // constructors + + constexpr local_shared_ptr() noexcept; + constexpr local_shared_ptr(std::nullptr_t) noexcept; + + template explicit local_shared_ptr(Y * p); + + template local_shared_ptr(Y * p, D d); + template local_shared_ptr(std::nullptr_t p, D d); + + template local_shared_ptr(Y * p, D d, A a); + template local_shared_ptr(std::nullptr_t p, D d, A a); + + local_shared_ptr(local_shared_ptr const & r) noexcept; + template local_shared_ptr(local_shared_ptr const & r) noexcept; + + local_shared_ptr(local_shared_ptr && r) noexcept; + template local_shared_ptr(local_shared_ptr && r) noexcept; + + template local_shared_ptr( shared_ptr const & r ); + template local_shared_ptr( shared_ptr && r ); + + template local_shared_ptr(local_shared_ptr const & r, element_type * p) noexcept; + template local_shared_ptr(local_shared_ptr && r, element_type * p) noexcept; + + template local_shared_ptr(std::unique_ptr && r); + + // destructor + + ~local_shared_ptr() noexcept; + + // assignment + + local_shared_ptr & operator=(local_shared_ptr const & r) noexcept; + template local_shared_ptr & operator=(local_shared_ptr const & r) noexcept; + + local_shared_ptr & operator=(local_shared_ptr const && r) noexcept; + template local_shared_ptr & operator=(local_shared_ptr const && r) noexcept; + + template local_shared_ptr & operator=(std::unique_ptr && r); + + local_shared_ptr & operator=(std::nullptr_t) noexcept; + + // reset + + void reset() noexcept; + + template void reset(Y * p); + template void reset(Y * p, D d); + template void reset(Y * p, D d, A a); + + template void reset(local_shared_ptr const & r, element_type * p) noexcept; + template void reset(local_shared_ptr && r, element_type * p) noexcept; + + // accessors + + T & operator*() const noexcept; // only valid when T is not an array type + T * operator->() const noexcept; // only valid when T is not an array type + + // only valid when T is an array type + element_type & operator[](std::ptrdiff_t i) const noexcept; + + element_type * get() const noexcept; + + long local_use_count() const noexcept; + + // conversions + + explicit operator bool() const noexcept; + + template operator shared_ptr() const noexcept; + template operator weak_ptr() const noexcept; + + // swap + + void swap(local_shared_ptr & b) noexcept; + + // owner_before + + template bool owner_before(local_shared_ptr const & rhs) const noexcept; + }; + + // comparisons + + template + bool operator==(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; + template + bool operator==(local_shared_ptr const & a, shared_ptr const & b) noexcept; + template + bool operator==(shared_ptr const & a, local_shared_ptr const & b) noexcept; + + template + bool operator!=(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; + template + bool operator!=(local_shared_ptr const & a, shared_ptr const & b) noexcept; + template + bool operator!=(shared_ptr const & a, local_shared_ptr const & b) noexcept; + + template bool operator==(local_shared_ptr const & p, std::nullptr_t) noexcept; + template bool operator==(std::nullptr_t, local_shared_ptr const & p) noexcept; + + template bool operator!=(local_shared_ptr const & p, std::nullptr_t) noexcept; + template bool operator!=(std::nullptr_t, local_shared_ptr const & p) noexcept; + + template + bool operator<(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; + + // swap + + template void swap(local_shared_ptr & a, local_shared_ptr & b) noexcept; + + // get_pointer + + template + typename local_shared_ptr::element_type * + get_pointer(local_shared_ptr const & p) noexcept; + + // casts + + template + local_shared_ptr static_pointer_cast(local_shared_ptr const & r) noexcept; + + template + local_shared_ptr const_pointer_cast(local_shared_ptr const & r) noexcept; + + template + local_shared_ptr dynamic_pointer_cast(local_shared_ptr const & r) noexcept; + + template + local_shared_ptr reinterpret_pointer_cast(local_shared_ptr const & r) noexcept; + + // stream I/O + + template + std::basic_ostream & + operator<< (std::basic_ostream & os, local_shared_ptr const & p); + + // get_deleter + + template D * get_deleter(local_shared_ptr const & p) noexcept; +} +``` + +## Members + +### element_type +``` +typedef ... element_type; +``` +`element_type` is `T` when `T` is not an array type, and `U` when `T` is `U[]` or `U[N]`. + +### default constructor +``` +constexpr local_shared_ptr() noexcept; +``` +``` +constexpr local_shared_ptr(std::nullptr_t) noexcept; +``` +[none] +* {blank} ++ +Effects:: Constructs an empty `local_shared_ptr`. +Postconditions:: `local_use_count() == 0 && get() == 0`. + +### pointer constructor +``` +template explicit local_shared_ptr(Y * p); +``` +[none] +* {blank} ++ +Effects:: Constructs a `local_shared_ptr` that owns `shared_ptr( p )`. + +Postconditions:: `local_use_count() == 1 && get() == p`. + +Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. + +### constructors taking a deleter +``` +template local_shared_ptr(Y * p, D d); +``` +``` +template local_shared_ptr(std::nullptr_t p, D d); +``` +[none] +* {blank} ++ +Effects:: Constructs a `local_shared_ptr` that owns `shared_ptr( p, d )`. + +Postconditions:: `local_use_count() == 1 && get() == p`. + +Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. + +``` +template local_shared_ptr(Y * p, D d, A a); +``` +``` +template local_shared_ptr(std::nullptr_t p, D d, A a); +``` +[none] +* {blank} ++ +Effects:: Constructs a `local_shared_ptr` that owns `shared_ptr( p, d, a )`. + +Postconditions:: `local_use_count() == 1 && get() == p`. + +Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. + +### copy and converting constructors +``` +local_shared_ptr(local_shared_ptr const & r) noexcept; +``` +``` +template local_shared_ptr(local_shared_ptr const & r) noexcept; +``` +[none] +* {blank} ++ +Requires:: `Y*` should be convertible to `T*`. + +Effects:: If `r` is empty, constructs an empty `local_shared_ptr`; otherwise, constructs a `local_shared_ptr` that shares ownership with `r`. + +Postconditions:: `get() == r.get() && local_use_count() == r.local_use_count()`. + +### move constructors +``` +local_shared_ptr(local_shared_ptr && r) noexcept; +``` +``` +template local_shared_ptr(local_shared_ptr && r) noexcept; +``` +[none] +* {blank} ++ +Requires:: `Y*` should be convertible to `T*`. + +Effects:: Move-constructs a `local_shared_ptr` from `r`. + +Postconditions:: `*this` contains the old value of `r`. `r` is empty and `r.get() == 0`. + +### shared_ptr constructor +``` +template local_shared_ptr( shared_ptr const & r ); +``` +``` +template local_shared_ptr( shared_ptr && r ); +``` +[none] +* {blank} ++ +Effects:: Constructs a `local_shared_ptr` that owns `r`. + +Postconditions:: `local_use_count() == 1`. `get()` returns the old value of `r.get()`. + +Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. + +### aliasing constructor +``` +template local_shared_ptr(local_shared_ptr const & r, element_type * p) noexcept; +``` +[none] +* {blank} ++ +Effects:: constructs a `local_shared_ptr` that shares ownership with `r` and stores `p`. + +Postconditions:: `get() == p && local_use_count() == r.local_use_count()`. + +### aliasing move constructor +``` +template local_shared_ptr(local_shared_ptr && r, element_type * p) noexcept; +``` +[none] +* {blank} ++ +Effects:: Move-constructs a `local_shared_ptr` from `r`, while storing `p` instead. + +Postconditions:: `get() == p` and `local_use_count()` equals the old count of `r`. `r` is empty and `r.get() == 0`. + +### unique_ptr constructor +``` +template local_shared_ptr(std::unique_ptr && r); +``` +[none] +* {blank} ++ +Requires:: `Y*` should be convertible to `T*`. + +Effects:: +- When `r.get() == 0`, equivalent to `local_shared_ptr()`; +- Otherwise, constructs a `local_shared_ptr` that owns `shared_ptr( std::move(r) )`. + +Throws:: `std::bad_alloc`, or an implementation-defined exception when a resource other than memory could not be obtained. + +Exception safety:: If an exception is thrown, the constructor has no effect. + +### destructor +``` +~local_shared_ptr() noexcept; +``` +[none] +* {blank} ++ +Effects:: +- If `*this` is empty, or shares ownership with another `local_shared_ptr` instance (`local_use_count() > 1`), there are no side effects. +- Otherwise, destroys the owned `shared_ptr`. + +### assignment +``` +local_shared_ptr & operator=(local_shared_ptr const & r) noexcept; +``` +``` +template local_shared_ptr & operator=(local_shared_ptr const & r) noexcept; +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr(r).swap(*this)`. +Returns:: `*this`. + +``` +local_shared_ptr & operator=(local_shared_ptr && r) noexcept; +``` +``` +template local_shared_ptr & operator=(local_shared_ptr && r) noexcept; +``` +``` +template local_shared_ptr & operator=(std::unique_ptr && r); +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr(std::move(r)).swap(*this)`. +Returns:: `*this`. + +``` +local_shared_ptr & operator=(std::nullptr_t) noexcept; +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr().swap(*this)`. +Returns:: `*this`. + +### reset +``` +void reset() noexcept; +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr().swap(*this)`. + +``` +template void reset(Y * p); +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr(p).swap(*this)`. + +``` +template void reset(Y * p, D d); +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr(p, d).swap(*this)`. + +``` +template void reset(Y * p, D d, A a); +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr(p, d, a).swap(*this)`. + +``` +template void reset(local_shared_ptr const & r, element_type * p) noexcept; +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr(r, p).swap(*this)`. + +``` +template void reset(local_shared_ptr && r, element_type * p) noexcept; +``` +[none] +* {blank} ++ +Effects:: Equivalent to `local_shared_ptr(std::move(r), p).swap(*this)`. + +### indirection +``` +T & operator*() const noexcept; +``` +[none] +* {blank} ++ +Requires:: `T` should not be an array type. +Returns:: `*get()`. + +``` +T * operator->() const noexcept; +``` +[none] +* {blank} ++ +Requires:: `T` should not be an array type. +Returns:: `get()`. + +``` +element_type & operator[](std::ptrdiff_t i) const noexcept; +``` +[none] +* {blank} ++ +Requires:: `T` should be an array type. The stored pointer must not be 0. `i >= 0`. If `T` is `U[N]`, `i < N`. +Returns:: `get()[i]`. + +### get + +``` +element_type * get() const noexcept; +``` +[none] +* {blank} ++ +Returns:: The stored pointer. + +### local_use_count +``` +long local_use_count() const noexcept; +``` +[none] +* {blank} ++ +Returns:: The number of `local_shared_ptr` objects, `*this` included, that share ownership with `*this`, or 0 when `*this` is empty. + +### conversions +``` +explicit operator bool() const noexcept; +``` +[none] +* {blank} ++ +Returns:: `get() != 0`. + +NOTE: On C++03 compilers, the return value is of an unspecified type. + +``` +template operator shared_ptr() const noexcept; +``` +``` +template operator weak_ptr() const noexcept; +``` +[none] +* {blank} ++ +Requires:: `T*` should be convertible to `Y*`. +Returns:: a copy of the owned `shared_ptr`. + +### swap +``` +void swap(local_shared_ptr & b) noexcept; +``` +[none] +* {blank} ++ +Effects:: Exchanges the contents of the two smart pointers. + +### owner_before +``` +template bool owner_before(local_shared_ptr const & rhs) const noexcept; +``` +[none] +* {blank} ++ +Effects:: See the description of `operator<`. + +## Free Functions + +### comparison +``` +template + bool operator==(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; +``` +``` +template + bool operator==(local_shared_ptr const & a, shared_ptr const & b) noexcept; +``` +``` +template + bool operator==(shared_ptr const & a, local_shared_ptr const & b) noexcept; +``` +[none] +* {blank} ++ +Returns:: `a.get() == b.get()`. + +``` +template + bool operator!=(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; +``` +``` +template + bool operator!=(local_shared_ptr const & a, shared_ptr const & b) noexcept; +``` +``` +template + bool operator!=(shared_ptr const & a, local_shared_ptr const & b) noexcept; +``` +[none] +* {blank} ++ +Returns:: `a.get() != b.get()`. + +``` +template bool operator==(local_shared_ptr const & p, std::nullptr_t) noexcept; +``` +``` +template bool operator==(std::nullptr_t, local_shared_ptr const & p) noexcept; +``` +[none] +* {blank} ++ +Returns:: `p.get() == 0`. + +``` +template bool operator!=(local_shared_ptr const & p, std::nullptr_t) noexcept; +``` +``` +template bool operator!=(std::nullptr_t, local_shared_ptr const & p) noexcept; +``` +[none] +* {blank} ++ +Returns:: `p.get() != 0`. + +``` +template + bool operator<(local_shared_ptr const & a, local_shared_ptr const & b) noexcept; +``` +[none] +* {blank} ++ +Returns:: An unspecified value such that + - `operator<` is a strict weak ordering as described in section [lib.alg.sorting] of the {cpp} standard; + - under the equivalence relation defined by `operator<`, `!(a < b) && !(b < a)`, two `local_shared_ptr` instances + are equivalent if and only if they share ownership or are both empty. + +NOTE: Allows `local_shared_ptr` objects to be used as keys in associative containers. + +NOTE: The rest of the comparison operators are omitted by design. + +### swap +``` +template void swap(local_shared_ptr & a, local_shared_ptr & b) noexcept; +``` +[none] +* {blank} ++ +Effects:: Equivalent to `a.swap(b)`. + +### get_pointer +``` +template + typename local_shared_ptr::element_type * + get_pointer(local_shared_ptr const & p) noexcept; +``` +[none] +* {blank} ++ +Returns:: `p.get()`. + +NOTE: Provided as an aid to generic programming. Used by `mem_fn`. + +### static_pointer_cast +``` +template + local_shared_ptr static_pointer_cast(local_shared_ptr const & r) noexcept; +``` +[none] +* {blank} ++ +Requires:: The expression `static_cast( (U*)0 )` must be well-formed. +Returns:: `local_shared_ptr( r, static_cast::element_type*>(r.get()) )`. + +CAUTION: The seemingly equivalent expression `local_shared_ptr(static_cast(r.get()))` will eventually +result in undefined behavior, attempting to delete the same object twice. + +### const_pointer_cast +``` +template + local_shared_ptr const_pointer_cast(local_shared_ptr const & r) noexcept; +``` +[none] +* {blank} ++ +Requires:: The expression `const_cast( (U*)0 )` must be well-formed. +Returns:: `local_shared_ptr( r, const_cast::element_type*>(r.get()) )`. + +### dynamic_pointer_cast +``` +template + local_shared_ptr dynamic_pointer_cast(local_shared_ptr const & r) noexcept; +``` +[none] +* {blank} ++ +Requires:: The expression `dynamic_cast( (U*)0 )` must be well-formed. +Returns:: + - When `dynamic_cast::element_type*>(r.get())` returns a nonzero value `p`, `local_shared_ptr(r, p)`; + - Otherwise, `local_shared_ptr()`. + +### reinterpret_pointer_cast +``` +template + local_shared_ptr reinterpret_pointer_cast(local_shared_ptr const & r) noexcept; +``` +[none] +* {blank} ++ +Requires:: The expression `reinterpret_cast( (U*)0 )` must be well-formed. +Returns:: `local_shared_ptr( r, reinterpret_cast::element_type*>(r.get()) )`. + +### operator<< +``` +template + std::basic_ostream & + operator<< (std::basic_ostream & os, local_shared_ptr const & p); +``` +[none] +* {blank} ++ +Effects:: `os << p.get();`. +Returns:: `os`. + +### get_deleter +``` +template + D * get_deleter(local_shared_ptr const & p) noexcept; +``` +[none] +* {blank} ++ +Returns:: If `*this` owns a `shared_ptr` instance `p`, `get_deleter( p )`, otherwise 0. +