From 738e360f403353a0768c952d59999cab2e438e3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Fri, 29 Aug 2014 10:28:09 +0200 Subject: [PATCH] Improved move-only deleters in C++03, now they can be caught as rvalues. --- include/boost/move/unique_ptr.hpp | 171 ++++++++++++++++-------------- test/unique_ptr.cpp | 148 ++++++++++---------------- 2 files changed, 146 insertions(+), 173 deletions(-) diff --git a/include/boost/move/unique_ptr.hpp b/include/boost/move/unique_ptr.hpp index f9b4128..f86ffc3 100644 --- a/include/boost/move/unique_ptr.hpp +++ b/include/boost/move/unique_ptr.hpp @@ -41,17 +41,37 @@ namespace boost{ namespace move_detail { +//////////////////////////////////////////// +// deleter types +//////////////////////////////////////////// +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +template +class is_noncopyable +{ + typedef char true_t; + class false_t { char dummy[2]; }; + template static false_t dispatch(...); + template static true_t dispatch(typename U::boost_move_no_copy_constructor_or_assign*); + public: + static const bool value = sizeof(dispatch(0)) == sizeof(true_t); +}; +#endif //defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template struct deleter_types { typedef typename add_lvalue_reference::type del_ref; typedef typename add_const_lvalue_reference::type del_cref; + #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES typedef typename if_c < is_lvalue_reference::value, D, del_cref >::type deleter_arg_type1; - #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - typedef typename remove_reference::type && deleter_arg_type2; + typedef typename remove_reference::type && deleter_arg_type2; #else - typedef ::boost::rv &deleter_arg_type2; + typedef typename if_c + < is_noncopyable::value, nat, del_cref>::type non_ref_deleter_arg1; + typedef typename if_c< is_lvalue_reference::value + , D, non_ref_deleter_arg1 >::type deleter_arg_type1; + typedef ::boost::rv & deleter_arg_type2; #endif }; @@ -61,10 +81,9 @@ struct deleter_types template ::value || is_reference::value > struct unique_ptr_data { - typedef typename deleter_types::deleter_arg_type1 deleter_arg_type1; - typedef typename deleter_types::deleter_arg_type2 deleter_arg_type2; - typedef typename deleter_types::del_ref del_ref; - typedef typename deleter_types::del_cref del_cref; + typedef typename deleter_types::deleter_arg_type1 deleter_arg_type1; + typedef typename deleter_types::del_ref del_ref; + typedef typename deleter_types::del_cref del_cref; unique_ptr_data() BOOST_NOEXCEPT : m_p(), d() @@ -78,13 +97,9 @@ struct unique_ptr_data : m_p(p), d(d1) {} - unique_ptr_data(P p, deleter_arg_type2 d2) BOOST_NOEXCEPT - : m_p(p), d(::boost::move(d2)) - {} - template unique_ptr_data(P p, BOOST_FWD_REF(U) d) BOOST_NOEXCEPT - : m_p(::boost::forward(p)), d(::boost::forward(d)) + : m_p(p), d(::boost::forward(d)) {} del_ref deleter() { return d; } @@ -102,16 +117,15 @@ template struct unique_ptr_data : private D { - typedef typename deleter_types::deleter_arg_type1 deleter_arg_type1; - typedef typename deleter_types::deleter_arg_type2 deleter_arg_type2; - typedef typename deleter_types::del_ref del_ref; - typedef typename deleter_types::del_cref del_cref; + typedef typename deleter_types::deleter_arg_type1 deleter_arg_type1; + typedef typename deleter_types::del_ref del_ref; + typedef typename deleter_types::del_cref del_cref; unique_ptr_data() BOOST_NOEXCEPT : D(), m_p() {} - unique_ptr_data(P p) BOOST_NOEXCEPT + explicit unique_ptr_data(P p) BOOST_NOEXCEPT : D(), m_p(p) {} @@ -119,17 +133,13 @@ struct unique_ptr_data : D(d1), m_p(p) {} - unique_ptr_data(P p, deleter_arg_type2 d2) BOOST_NOEXCEPT - : D(::boost::move(d2)), m_p(p) - {} - template unique_ptr_data(P p, BOOST_FWD_REF(U) d) BOOST_NOEXCEPT : D(::boost::forward(d)), m_p(p) {} - del_ref deleter() { return static_cast(*this); } - del_cref deleter() const{ return static_cast(*this); } + del_ref deleter() BOOST_NOEXCEPT { return static_cast(*this); } + del_cref deleter() const BOOST_NOEXCEPT { return static_cast(*this); } P m_p; @@ -445,11 +455,8 @@ class unique_ptr typedef move_detail::pointer_type pointer_type_obtainer; typedef bmd::unique_ptr_data data_type; - typedef typename data_type::deleter_arg_type1 deleter_arg_type1; - typedef typename data_type::deleter_arg_type2 deleter_arg_type2; - - typedef bmd::integral_constant - >::value > is_default_deleter_t; + typedef typename bmd::deleter_types::deleter_arg_type1 deleter_arg_type1; + typedef typename bmd::deleter_types::deleter_arg_type2 deleter_arg_type2; data_type m_data; #endif @@ -523,10 +530,18 @@ class unique_ptr //! - If D is an lvalue-reference type A&, then the signature is unique_ptr(pointer p, A& d). //! - If D is an lvalue-reference type const A&, then the signature is unique_ptr(pointer p, const A& d). //! + //! + //! Requires: Either + //! - D is not an lvalue-reference type and d is an lvalue or const rvalue. + //! D shall satisfy the requirements of CopyConstructible, and the copy constructor of D + //! shall not throw an exception. This unique_ptr will hold a copy of d. + //! - D is an lvalue-reference type and d is an lvalue. the type which D references need not be CopyConstructible nor + //! MoveConstructible. This unique_ptr will hold a D which refers to the lvalue d. + //! //! Effects: Constructs a unique_ptr object which owns p, initializing the stored pointer with p and //! initializing the deleter as described above. //! - //! Postconditions: get() == p.get_deleter() returns a reference to the stored deleter. If D is a + //! Postconditions: get() == p. get_deleter() returns a reference to the stored deleter. If D is a //! reference type then get_deleter() returns a reference to the lvalue d. //! //! Remarks: This constructor shall not participate in overload resolution unless: @@ -539,6 +554,8 @@ class unique_ptr : m_data(p, d1) {} + //! Effects: Same effects as template unique_ptr(Pointer p, deleter_arg_type1 d1) + //! and additionally get() == nullptr unique_ptr(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), BOOST_MOVE_SEEDOC(deleter_arg_type1) d1) BOOST_NOEXCEPT : m_data(pointer(), d1) {} @@ -548,10 +565,16 @@ class unique_ptr //! - If D is an lvalue-reference type A&, then the signature is unique_ptr(pointer p, A&& d). //! - If D is an lvalue-reference type const A&, then the signature is unique_ptr(pointer p, const A&& d). //! + //! Requires: Either + //! - D is not an lvalue-reference type and d is a non-const rvalue. D + //! shall satisfy the requirements of MoveConstructible, and the move constructor + //! of D shall not throw an exception. This unique_ptr will hold a value move constructed from d. + //! - D is an lvalue-reference type and d is an rvalue, the program is ill-formed. + //! //! Effects: Constructs a unique_ptr object which owns p, initializing the stored pointer with p and //! initializing the deleter as described above. //! - //! Postconditions: get() == p.get_deleter() returns a reference to the stored deleter. If D is a + //! Postconditions: get() == p. get_deleter() returns a reference to the stored deleter. If D is a //! reference type then get_deleter() returns a reference to the lvalue d. //! //! Remarks: This constructor shall not participate in overload resolution unless: @@ -564,6 +587,8 @@ class unique_ptr : m_data(p, ::boost::move(d2)) {} + //! Effects: Same effects as template unique_ptr(Pointer p, deleter_arg_type2 d2) + //! and additionally get() == nullptr unique_ptr(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), BOOST_MOVE_SEEDOC(deleter_arg_type2) d2) BOOST_NOEXCEPT : m_data(pointer(), ::boost::move(d2)) {} @@ -657,10 +682,7 @@ class unique_ptr //! //! Returns: *this. unique_ptr& operator=(BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) BOOST_NOEXCEPT - { - this->reset(); - return *this; - } + { this->reset(); return *this; } //! Requires: get() != nullptr. //! @@ -668,7 +690,7 @@ class unique_ptr //! //! Remarks::type) - operator*() const + operator*() const BOOST_NOEXCEPT { BOOST_STATIC_ASSERT((!bmd::is_array::value)); return *get(); @@ -680,7 +702,7 @@ class unique_ptr //! //! Remarks::type) - operator[](size_t i) const + operator[](size_t i) const BOOST_NOEXCEPT { BOOST_STATIC_ASSERT((bmd::is_array::value)); const pointer p = this->get(); @@ -698,7 +720,9 @@ class unique_ptr pointer operator->() const BOOST_NOEXCEPT { BOOST_STATIC_ASSERT((!bmd::is_array::value)); - return get(); + const pointer p = this->get(); + BOOST_ASSERT(p); + return p; } //! Returns: The stored pointer. @@ -732,7 +756,6 @@ class unique_ptr : bmd::explicit_bool_arg(0); } - //! Postcondition: get() == nullptr. //! //! Returns: The value get() had at the start of the call to release. @@ -839,88 +862,76 @@ inline bool operator>=(const unique_ptr &x, const unique_ptr &y) //! Returns:!x. //! -template -inline bool operator==(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) BOOST_NOEXCEPT +template +inline bool operator==(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) BOOST_NOEXCEPT { return !x; } //! Returns:!x. //! -template -inline bool operator==(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) BOOST_NOEXCEPT +template +inline bool operator==(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) BOOST_NOEXCEPT { return !x; } //! Returns: (bool)x. //! -template -inline bool operator!=(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) BOOST_NOEXCEPT +template +inline bool operator!=(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) BOOST_NOEXCEPT { return !!x; } //! Returns: (bool)x. //! -template -inline bool operator!=(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) BOOST_NOEXCEPT +template +inline bool operator!=(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) BOOST_NOEXCEPT { return !!x; } -//! Requires: operator shall induce a strict weak ordering on unique_ptr::pointer values. +//! Requires: operator shall induce a strict weak ordering on unique_ptr::pointer values. //! //! Returns: Returns x.get() < pointer(). -template -inline bool operator<(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) -{ - typedef typename unique_ptr::pointer pointer; - return x.get() < pointer(); -} +template +inline bool operator<(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) +{ return x.get() < unique_ptr::pointer(); } -//! Requires: operator shall induce a strict weak ordering on unique_ptr::pointer values. +//! Requires: operator shall induce a strict weak ordering on unique_ptr::pointer values. //! //! Returns: Returns pointer() < x.get(). -template -inline bool operator<(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) -{ - typedef typename unique_ptr::pointer pointer; - return pointer() < x.get(); -} +template +inline bool operator<(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) +{ return unique_ptr::pointer() < x.get(); } //! Returns: nullptr < x. //! -template -inline bool operator>(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) -{ - typedef typename unique_ptr::pointer pointer; - return x.get() > pointer(); -} +template +inline bool operator>(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) +{ return x.get() > unique_ptr::pointer(); } //! Returns: x < nullptr. //! -template -inline bool operator>(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) -{ - typedef typename unique_ptr::pointer pointer; - return pointer() > x.get(); -} +template +inline bool operator>(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) +{ return unique_ptr::pointer() > x.get(); } //! Returns: !(nullptr < x). //! -template -inline bool operator<=(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) +template +inline bool operator<=(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) { return !(bmd::nullptr_type() < x); } //! Returns: !(x < nullptr). //! -template -inline bool operator<=(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) +template +inline bool operator<=(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) { return !(x < bmd::nullptr_type()); } //! Returns: !(x < nullptr). //! -template -inline bool operator>=(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) +template +inline bool operator>=(const unique_ptr &x, BOOST_MOVE_DOC0PTR(bmd::nullptr_type)) { return !(x < bmd::nullptr_type()); } //! Returns: !(nullptr < x). //! -template -inline bool operator>=(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) +template +inline bool operator>=(BOOST_MOVE_DOC0PTR(bmd::nullptr_type), const unique_ptr &x) { return !(bmd::nullptr_type() < x); } } //namespace movelib { diff --git a/test/unique_ptr.cpp b/test/unique_ptr.cpp index e242406..e52a43d 100644 --- a/test/unique_ptr.cpp +++ b/test/unique_ptr.cpp @@ -58,22 +58,6 @@ class def_constr_deleter { ++state_; is_array ? delete []p : delete p; } }; -template -struct enable_if_conversion_acceptable - : ::boost::move_detail::enable_if_c - < OtherIsArray && ::boost::move_detail::is_same_cvelement_and_convertible::value - , Type - > -{}; - -template -struct enable_if_conversion_acceptable - : ::boost::move_detail::enable_if_c - < !OtherIsArray && ::boost::move_detail::is_convertible::value - , Type - > -{}; - //A deleter that can be copy constructed template class copy_constr_deleter @@ -88,24 +72,13 @@ class copy_constr_deleter template copy_constr_deleter(const copy_constr_deleter& - , typename enable_if_conversion_acceptable - < copy_constr_deleter::is_array - , is_array - , typename copy_constr_deleter::element_type - , element_type - >::type* = 0) + , typename boost::move_detail::enable_def_del::type* =0) { state_ = 5; } explicit copy_constr_deleter(int s) : state_(s) {} template - typename enable_if_conversion_acceptable - < copy_constr_deleter::is_array - , is_array - , typename copy_constr_deleter::element_type - , element_type - , copy_constr_deleter& - >::type + typename boost::move_detail::enable_def_del::type operator=(const copy_constr_deleter &d) { state_ = d.state(); @@ -145,12 +118,7 @@ class move_constr_deleter template move_constr_deleter(BOOST_RV_REF(move_constr_deleter) d - , typename enable_if_conversion_acceptable - < move_constr_deleter::is_array - , is_array - , typename move_constr_deleter::element_type - , element_type - >::type* = 0) + , typename boost::move_detail::enable_def_del::type* =0) : state_(d.state()) { d.set_state(0); } @@ -162,13 +130,7 @@ class move_constr_deleter } template - typename enable_if_conversion_acceptable - < move_constr_deleter::is_array - , is_array - , typename move_constr_deleter::element_type - , element_type - , move_constr_deleter& - >::type + typename boost::move_detail::enable_def_del::type operator=(BOOST_RV_REF(move_constr_deleter) d) { state_ = d.state(); @@ -318,7 +280,6 @@ void test() } //namespace unique_ptr_asgn_move_convert01{ - //////////////////////////////// // unique_ptr_asgn_move_convert02 //////////////////////////////// @@ -362,8 +323,6 @@ void test() BOOST_TEST(A::count == 0); } - - } //namespace unique_ptr_asgn_move_convert02{ //////////////////////////////// @@ -508,50 +467,6 @@ void test() } //unique_ptr_asgn_move01 -//////////////////////////////// -// unique_ptr_zero -//////////////////////////////// -namespace unique_ptr_zero { - -// test initialization/assignment from zero - -void test() -{ - //Single unique_ptr - reset_counters(); - { - bml::unique_ptr s2(0); - BOOST_TEST(A::count == 0); - } - BOOST_TEST(A::count == 0); - { - bml::unique_ptr s2(new A); - BOOST_TEST(A::count == 1); - s2 = 0; - BOOST_TEST(A::count == 0); - BOOST_TEST(s2.get() == 0); - } - BOOST_TEST(A::count == 0); - - //Array unique_ptr - { - bml::unique_ptr s2(0); - BOOST_TEST(A::count == 0); - } - BOOST_TEST(A::count == 0); - { - bml::unique_ptr s2(new A[2]); - BOOST_TEST(A::count == 2); - s2 = 0; - BOOST_TEST(A::count == 0); - BOOST_TEST(s2.get() == 0); - } - BOOST_TEST(A::count == 0); -} - -} //namespace unique_ptr_zero { - - //////////////////////////////// // unique_ptr_ctor_default01 //////////////////////////////// @@ -710,7 +625,6 @@ void test() BOOST_TEST(B::count == 0); } - } //namespace unique_ptr_ctor_move_convert02{ //////////////////////////////// @@ -801,8 +715,6 @@ void test() } //namespace unique_ptr_ctor_move_convert04{ - - //////////////////////////////// // unique_ptr_ctor_move_convert05 //////////////////////////////// @@ -1072,6 +984,9 @@ void test() bml::unique_ptr > s(p, ::boost::move(d)); BOOST_TEST(s.get() == p); BOOST_TEST(s.get_deleter().state() == 5); + bml::unique_ptr > s2(s.release(), move_constr_deleter(6)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s2.get_deleter().state() == 6); } BOOST_TEST(A::count == 0); //Array unique_ptr @@ -1083,6 +998,9 @@ void test() bml::unique_ptr > s(p, ::boost::move(d)); BOOST_TEST(s.get() == p); BOOST_TEST(s.get_deleter().state() == 5); + bml::unique_ptr > s2(s.release(), move_constr_deleter(6)); + BOOST_TEST(s2.get() == p); + BOOST_TEST(s2.get_deleter().state() == 6); } BOOST_TEST(A::count == 0); } @@ -1847,6 +1765,50 @@ void test() } //namespace unique_ptr_observers_op_index{ +//////////////////////////////// +// unique_ptr_zero +//////////////////////////////// +namespace unique_ptr_zero { + +// test initialization/assignment from zero + +void test() +{ + //Single unique_ptr + reset_counters(); + { + bml::unique_ptr s2(0); + BOOST_TEST(A::count == 0); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr s2(new A); + BOOST_TEST(A::count == 1); + s2 = 0; + BOOST_TEST(A::count == 0); + BOOST_TEST(s2.get() == 0); + } + BOOST_TEST(A::count == 0); + + //Array unique_ptr + { + bml::unique_ptr s2(0); + BOOST_TEST(A::count == 0); + } + BOOST_TEST(A::count == 0); + { + bml::unique_ptr s2(new A[2]); + BOOST_TEST(A::count == 2); + s2 = 0; + BOOST_TEST(A::count == 0); + BOOST_TEST(s2.get() == 0); + } + BOOST_TEST(A::count == 0); +} + +} //namespace unique_ptr_zero { + + //////////////////////////////// // unique_ptr_nullptr //////////////////////////////// @@ -1939,7 +1901,7 @@ void test() int main() { //General - pointer_type::test(); + pointer_type::test(); //Assignment unique_ptr_asgn_move_convert01::test();