Compare commits

...

9 Commits

Author SHA1 Message Date
Peter Dimov
8340a13539 Merge branch 'feature/move-up-deleter' into feature/move-only-deleter 2021-05-11 18:03:35 +03:00
Peter Dimov
098d0f4ce3 Disable sp_unique_ptr_test2 on msvc-10.0 2021-05-11 15:54:21 +03:00
Peter Dimov
fec5fb97c8 Enable move-only deleters in the nullptr_t constructors 2021-05-11 02:15:27 +03:00
Peter Dimov
b52d7548b3 Enable move-only deleters in the allocator constructor 2021-05-11 02:05:28 +03:00
Peter Dimov
594c7485a5 Enable move-only deleters 2021-05-11 01:59:01 +03:00
Peter Dimov
d751041fb9 Add more test cases to sp_unique_ptr_test2 2021-05-11 01:33:48 +03:00
Peter Dimov
d41546ddce Move the unique_ptr deleter instead of copying it 2021-05-11 01:20:02 +03:00
Peter Dimov
f3424e74e8 Update .github/workflows 2021-04-19 18:53:52 +03:00
Peter Dimov
0eee7efd54 Update .github/workflows 2021-04-19 18:18:38 +03:00
7 changed files with 399 additions and 5 deletions

View File

@@ -42,6 +42,7 @@ jobs:
- toolset: gcc-8 - toolset: gcc-8
cxxstd: "03,11,14,17,2a" cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04 os: ubuntu-18.04
install: g++-8
- toolset: gcc-9 - toolset: gcc-9
cxxstd: "03,11,14,17,2a" cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04 os: ubuntu-18.04
@@ -50,7 +51,7 @@ jobs:
os: ubuntu-18.04 os: ubuntu-18.04
- toolset: clang - toolset: clang
compiler: clang++-3.5 compiler: clang++-3.5
cxxstd: "03,11,14" cxxstd: "03,11"
os: ubuntu-16.04 os: ubuntu-16.04
install: clang-3.5 install: clang-3.5
- toolset: clang - toolset: clang
@@ -87,6 +88,7 @@ jobs:
compiler: clang++-6.0 compiler: clang++-6.0
cxxstd: "03,11,14,17" cxxstd: "03,11,14,17"
os: ubuntu-18.04 os: ubuntu-18.04
install: clang-6.0
- toolset: clang - toolset: clang
compiler: clang++-7 compiler: clang++-7
cxxstd: "03,11,14,17" cxxstd: "03,11,14,17"
@@ -96,6 +98,7 @@ jobs:
compiler: clang++-8 compiler: clang++-8
cxxstd: "03,11,14,17,2a" cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04 os: ubuntu-20.04
install: clang-8
- toolset: clang - toolset: clang
compiler: clang++-9 compiler: clang++-9
cxxstd: "03,11,14,17,2a" cxxstd: "03,11,14,17,2a"
@@ -104,6 +107,10 @@ jobs:
compiler: clang++-10 compiler: clang++-10
cxxstd: "03,11,14,17,2a" cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04 os: ubuntu-20.04
- toolset: clang
compiler: clang++-11
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
- toolset: clang - toolset: clang
cxxstd: "03,11,14,17,2a" cxxstd: "03,11,14,17,2a"
os: macos-10.15 os: macos-10.15

View File

@@ -387,7 +387,7 @@ public:
{ {
typedef typename sp_convert_reference<D>::type D2; typedef typename sp_convert_reference<D>::type D2;
D2 d2( r.get_deleter() ); D2 d2( static_cast<D&&>( r.get_deleter() ) );
pi_ = new sp_counted_impl_pd< typename std::unique_ptr<Y, D>::pointer, D2 >( r.get(), d2 ); pi_ = new sp_counted_impl_pd< typename std::unique_ptr<Y, D>::pointer, D2 >( r.get(), d2 );
#ifdef BOOST_NO_EXCEPTIONS #ifdef BOOST_NO_EXCEPTIONS

View File

@@ -145,7 +145,7 @@ template<class P, class D> class BOOST_SYMBOL_VISIBLE sp_counted_impl_pd: public
private: private:
P ptr; // copy constructor must not throw P ptr; // copy constructor must not throw
D del; // copy constructor must not throw D del; // copy/move constructor must not throw
sp_counted_impl_pd( sp_counted_impl_pd const & ); sp_counted_impl_pd( sp_counted_impl_pd const & );
sp_counted_impl_pd & operator= ( sp_counted_impl_pd const & ); sp_counted_impl_pd & operator= ( sp_counted_impl_pd const & );
@@ -156,10 +156,20 @@ public:
// pre: d(p) must not throw // pre: d(p) must not throw
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
sp_counted_impl_pd( P p, D & d ): ptr( p ), del( static_cast< D&& >( d ) )
{
}
#else
sp_counted_impl_pd( P p, D & d ): ptr( p ), del( d ) sp_counted_impl_pd( P p, D & d ): ptr( p ), del( d )
{ {
} }
#endif
sp_counted_impl_pd( P p ): ptr( p ), del() sp_counted_impl_pd( P p ): ptr( p ), del()
{ {
} }
@@ -218,7 +228,7 @@ template<class P, class D, class A> class BOOST_SYMBOL_VISIBLE sp_counted_impl_p
private: private:
P p_; // copy constructor must not throw P p_; // copy constructor must not throw
D d_; // copy constructor must not throw D d_; // copy/move constructor must not throw
A a_; // copy constructor must not throw A a_; // copy constructor must not throw
sp_counted_impl_pda( sp_counted_impl_pda const & ); sp_counted_impl_pda( sp_counted_impl_pda const & );
@@ -230,10 +240,20 @@ public:
// pre: d( p ) must not throw // pre: d( p ) must not throw
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
sp_counted_impl_pda( P p, D & d, A a ): p_( p ), d_( static_cast< D&& >( d ) ), a_( a )
{
}
#else
sp_counted_impl_pda( P p, D & d, A a ): p_( p ), d_( d ), a_( a ) sp_counted_impl_pda( P p, D & d, A a ): p_( p ), d_( d ), a_( a )
{ {
} }
#endif
sp_counted_impl_pda( P p, A a ): p_( p ), d_( a ), a_( a ) sp_counted_impl_pda( P p, A a ): p_( p ), d_( a ), a_( a )
{ {
} }

View File

@@ -374,39 +374,81 @@ 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) // shared_ptr will release p by calling d(p)
// //
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
template<class Y, class D> shared_ptr( Y * p, D d ): px( p ), pn( p, static_cast< D&& >( d ) )
{
boost::detail::sp_deleter_construct( this, p );
}
#else
template<class Y, class D> shared_ptr( Y * p, D d ): px( p ), pn( p, d ) template<class Y, class D> shared_ptr( Y * p, D d ): px( p ), pn( p, d )
{ {
boost::detail::sp_deleter_construct( this, p ); boost::detail::sp_deleter_construct( this, p );
} }
#endif
#if !defined( BOOST_NO_CXX11_NULLPTR ) #if !defined( BOOST_NO_CXX11_NULLPTR )
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
template<class D> shared_ptr( boost::detail::sp_nullptr_t p, D d ): px( p ), pn( p, static_cast< D&& >( d ) )
{
}
#else
template<class D> shared_ptr( boost::detail::sp_nullptr_t p, D d ): px( p ), pn( p, d ) template<class D> shared_ptr( boost::detail::sp_nullptr_t p, D d ): px( p ), pn( p, d )
{ {
} }
#endif
#endif #endif
// As above, but with allocator. A's copy constructor shall not throw. // As above, but with allocator. A's copy constructor shall not throw.
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
template<class Y, class D, class A> shared_ptr( Y * p, D d, A a ): px( p ), pn( p, static_cast< D&& >( d ), a )
{
boost::detail::sp_deleter_construct( this, p );
}
#else
template<class Y, class D, class A> shared_ptr( Y * p, D d, A a ): px( p ), pn( p, d, a ) template<class Y, class D, class A> shared_ptr( Y * p, D d, A a ): px( p ), pn( p, d, a )
{ {
boost::detail::sp_deleter_construct( this, p ); boost::detail::sp_deleter_construct( this, p );
} }
#endif
#if !defined( BOOST_NO_CXX11_NULLPTR ) #if !defined( BOOST_NO_CXX11_NULLPTR )
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
template<class D, class A> shared_ptr( boost::detail::sp_nullptr_t p, D d, A a ): px( p ), pn( p, static_cast< D&& >( d ), a )
{
}
#else
template<class D, class A> shared_ptr( boost::detail::sp_nullptr_t p, D d, A a ): px( p ), pn( p, d, a ) template<class D, class A> shared_ptr( boost::detail::sp_nullptr_t p, D d, A a ): px( p ), pn( p, d, a )
{ {
} }
#endif #endif
#endif
// generated copy constructor, destructor are fine... // generated copy constructor, destructor are fine...
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) #if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
@@ -693,6 +735,20 @@ public:
this_type( p ).swap( *this ); this_type( p ).swap( *this );
} }
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
template<class Y, class D> void reset( Y * p, D d )
{
this_type( p, static_cast< D&& >( d ) ).swap( *this );
}
template<class Y, class D, class A> void reset( Y * p, D d, A a )
{
this_type( p, static_cast< D&& >( d ), a ).swap( *this );
}
#else
template<class Y, class D> void reset( Y * p, D d ) template<class Y, class D> void reset( Y * p, D d )
{ {
this_type( p, d ).swap( *this ); this_type( p, d ).swap( *this );
@@ -703,6 +759,8 @@ public:
this_type( p, d, a ).swap( *this ); this_type( p, d, a ).swap( *this );
} }
#endif
template<class Y> void reset( shared_ptr<Y> const & r, element_type * p ) BOOST_SP_NOEXCEPT template<class Y> void reset( shared_ptr<Y> const & r, element_type * p ) BOOST_SP_NOEXCEPT
{ {
this_type( r, p ).swap( *this ); this_type( r, p ).swap( *this );

View File

@@ -408,3 +408,6 @@ run wp_unordered_test.cpp ;
run owner_hash_test.cpp ; run owner_hash_test.cpp ;
run sp_unordered_test.cpp ; run sp_unordered_test.cpp ;
run sp_unique_ptr_test2.cpp ;
run sp_move_only_deleter.cpp ;

View File

@@ -0,0 +1,153 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/shared_ptr.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#include <memory>
#include <utility>
#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<Y> 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<Y>( 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 );
}
{
YD del;
boost::shared_ptr<Y> p( new Y, std::move( del ), std::allocator<Y>() );
BOOST_TEST( Y::instances == 1 );
BOOST_TEST( del.moved_ );
p.reset( new Y, YD(), std::allocator<Y>() );
BOOST_TEST( Y::instances == 1 );
p = boost::shared_ptr<Y>( new Y, YD(), std::allocator<Y>() );
BOOST_TEST( Y::instances == 1 );
YD del2;
p.reset( new Y, std::move( del2 ), std::allocator<Y>() );
BOOST_TEST( Y::instances == 1 );
BOOST_TEST( del2.moved_ );
p.reset();
BOOST_TEST( Y::instances == 0 );
}
#if !defined( BOOST_NO_CXX11_NULLPTR )
{
boost::shared_ptr<Y> p( nullptr, YD() );
YD del;
p = boost::shared_ptr<Y>( nullptr, std::move( del ) );
BOOST_TEST( del.moved_ );
}
{
boost::shared_ptr<Y> p( nullptr, YD(), std::allocator<Y>() );
YD del;
p = boost::shared_ptr<Y>( nullptr, std::move( del ), std::allocator<Y>() );
BOOST_TEST( del.moved_ );
}
#endif
return boost::report_errors();
}
#endif

View File

@@ -0,0 +1,153 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/shared_ptr.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#include <memory>
#include <utility>
#if defined( BOOST_NO_CXX11_SMART_PTR )
BOOST_PRAGMA_MESSAGE("Skipping test because BOOST_NO_CXX11_SMART_PTR is defined")
int main() {}
#elif defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
BOOST_PRAGMA_MESSAGE("Skipping test because BOOST_NO_CXX11_RVALUE_REFERENCES is defined")
int main() {}
#elif defined(BOOST_MSVC) && BOOST_MSVC < 1700
BOOST_PRAGMA_MESSAGE("Skipping test because msvc-10.0 unique_ptr doesn't support move-only deleters")
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;
}
else
{
BOOST_ERROR( "YD::operator()(0) called" );
}
}
private:
YD( YD const & );
YD & operator=( YD const & );
};
int main()
{
BOOST_TEST( Y::instances == 0 );
{
std::unique_ptr<Y, YD> p( new Y );
BOOST_TEST( Y::instances == 1 );
boost::shared_ptr<Y> p2( std::move( p ) );
BOOST_TEST( Y::instances == 1 );
BOOST_TEST( p.get() == 0 );
BOOST_TEST( p.get_deleter().moved_ );
p2.reset();
BOOST_TEST( Y::instances == 0 );
}
{
std::unique_ptr<Y, YD> p( new Y );
BOOST_TEST( Y::instances == 1 );
boost::shared_ptr<void> p2( std::move( p ) );
BOOST_TEST( Y::instances == 1 );
BOOST_TEST( p.get() == 0 );
BOOST_TEST( p.get_deleter().moved_ );
p2.reset();
BOOST_TEST( Y::instances == 0 );
}
{
std::unique_ptr<Y, YD> p( new Y );
BOOST_TEST( Y::instances == 1 );
boost::shared_ptr<Y> p2;
p2 = std::move( p );
BOOST_TEST( Y::instances == 1 );
BOOST_TEST( p.get() == 0 );
BOOST_TEST( p.get_deleter().moved_ );
p2.reset();
BOOST_TEST( Y::instances == 0 );
}
{
std::unique_ptr<Y, YD> p( new Y );
BOOST_TEST( Y::instances == 1 );
boost::shared_ptr<void> p2( new int(0) );
p2 = std::move( p );
BOOST_TEST( Y::instances == 1 );
BOOST_TEST( p.get() == 0 );
BOOST_TEST( p.get_deleter().moved_ );
p2.reset();
BOOST_TEST( Y::instances == 0 );
}
return boost::report_errors();
}
#endif