From 594c7485a5db9bcbcad5743c3ded2c88984c938e Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 11 May 2021 01:59:01 +0300 Subject: [PATCH] Enable move-only deleters --- .../boost/smart_ptr/detail/shared_count.hpp | 2 +- .../smart_ptr/detail/sp_counted_impl.hpp | 8 +- include/boost/smart_ptr/shared_ptr.hpp | 24 +++- test/Jamfile | 1 + test/sp_move_only_deleter.cpp | 106 ++++++++++++++++++ 5 files changed, 136 insertions(+), 5 deletions(-) create mode 100644 test/sp_move_only_deleter.cpp diff --git a/include/boost/smart_ptr/detail/shared_count.hpp b/include/boost/smart_ptr/detail/shared_count.hpp index cb9eeb4..73a33ff 100644 --- a/include/boost/smart_ptr/detail/shared_count.hpp +++ b/include/boost/smart_ptr/detail/shared_count.hpp @@ -388,7 +388,7 @@ public: typedef typename sp_convert_reference::type D2; D2 d2( static_cast( r.get_deleter() ) ); - pi_ = new sp_counted_impl_pd< typename std::unique_ptr::pointer, D2 >( r.get(), static_cast< D2&& >( d2 ) ); + pi_ = new sp_counted_impl_pd< typename std::unique_ptr::pointer, D2 >( r.get(), d2 ); #ifdef BOOST_NO_EXCEPTIONS diff --git a/include/boost/smart_ptr/detail/sp_counted_impl.hpp b/include/boost/smart_ptr/detail/sp_counted_impl.hpp index 0cbb2ce..26628cc 100644 --- a/include/boost/smart_ptr/detail/sp_counted_impl.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_impl.hpp @@ -156,13 +156,15 @@ public: // pre: d(p) must not throw - sp_counted_impl_pd( P p, D & d ): ptr( p ), del( d ) +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + sp_counted_impl_pd( P p, D & d ): ptr( p ), del( static_cast< D&& >( d ) ) { } -#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) +#else - sp_counted_impl_pd( P p, D && d ): ptr( p ), del( static_cast< D&& >( d ) ) + sp_counted_impl_pd( P p, D & d ): ptr( p ), del( d ) { } diff --git a/include/boost/smart_ptr/shared_ptr.hpp b/include/boost/smart_ptr/shared_ptr.hpp index 4264b06..38dce70 100644 --- a/include/boost/smart_ptr/shared_ptr.hpp +++ b/include/boost/smart_ptr/shared_ptr.hpp @@ -374,16 +374,27 @@ public: } // - // Requirements: D's copy constructor must not throw + // Requirements: D's copy/move constructors must not throw // // shared_ptr will release p by calling d(p) // +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + template shared_ptr( Y * p, D d ): px( p ), pn( p, static_cast< D&& >( d ) ) + { + boost::detail::sp_deleter_construct( this, p ); + } + +#else + template shared_ptr( Y * p, D d ): px( p ), pn( p, d ) { boost::detail::sp_deleter_construct( this, p ); } +#endif + #if !defined( BOOST_NO_CXX11_NULLPTR ) template shared_ptr( boost::detail::sp_nullptr_t p, D d ): px( p ), pn( p, d ) @@ -693,11 +704,22 @@ public: this_type( p ).swap( *this ); } +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + template void reset( Y * p, D d ) + { + this_type( p, static_cast< D&& >( d ) ).swap( *this ); + } + +#else + template void reset( Y * p, D d ) { this_type( p, d ).swap( *this ); } +#endif + template void reset( Y * p, D d, A a ) { this_type( p, d, a ).swap( *this ); diff --git a/test/Jamfile b/test/Jamfile index 69a68a5..34ce46d 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -410,3 +410,4 @@ run owner_hash_test.cpp ; run sp_unordered_test.cpp ; run sp_unique_ptr_test2.cpp ; +run sp_move_only_deleter.cpp ; diff --git a/test/sp_move_only_deleter.cpp b/test/sp_move_only_deleter.cpp new file mode 100644 index 0000000..d879b7b --- /dev/null +++ b/test/sp_move_only_deleter.cpp @@ -0,0 +1,106 @@ +// Copyright 2021 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include +#include + +#if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + +BOOST_PRAGMA_MESSAGE("Skipping test because BOOST_NO_CXX11_RVALUE_REFERENCES is defined") +int main() {} + +#else + +struct Y +{ + static int instances; + + bool deleted_; + + Y(): deleted_( false ) + { + ++instances; + } + + ~Y() + { + BOOST_TEST( deleted_ ); + --instances; + } + +private: + + Y( Y const & ); + Y & operator=( Y const & ); +}; + +int Y::instances = 0; + +struct YD +{ + bool moved_; + + YD(): moved_( false ) + { + } + + YD( YD&& r ): moved_( false ) + { + r.moved_ = true; + } + + void operator()( Y* p ) const + { + BOOST_TEST( !moved_ ); + + if( p ) + { + p->deleted_ = true; + delete p; + } + } + +private: + + YD( YD const & ); + YD & operator=( YD const & ); +}; + +int main() +{ + BOOST_TEST( Y::instances == 0 ); + + { + YD del; + boost::shared_ptr p( new Y, std::move( del ) ); + + BOOST_TEST( Y::instances == 1 ); + BOOST_TEST( del.moved_ ); + + p.reset( new Y, YD() ); + + BOOST_TEST( Y::instances == 1 ); + + p = boost::shared_ptr( new Y, YD() ); + + BOOST_TEST( Y::instances == 1 ); + + YD del2; + p.reset( new Y, std::move( del2 ) ); + + BOOST_TEST( Y::instances == 1 ); + BOOST_TEST( del2.moved_ ); + + p.reset(); + BOOST_TEST( Y::instances == 0 ); + } + + return boost::report_errors(); +} + +#endif