diff --git a/doc/container.qbk b/doc/container.qbk index 981e87e..3ba6617 100644 --- a/doc/container.qbk +++ b/doc/container.qbk @@ -1220,6 +1220,9 @@ use [*Boost.Container]? There are several reasons for that: * [@https://svn.boost.org/trac/boost/ticket/12177 Trac #12177: ['"vector::priv_merge uses unqualified uintptr_t"]]. * [@https://svn.boost.org/trac/boost/ticket/12183 Trac #12183: ['"GCC 6.1 thinks boost::container::string violates strict aliasing"]]. * [@https://svn.boost.org/trac/boost/ticket/12286 Trac #12286: ['"PMR flat_map from Boost Container does not compile"]]. + * [@https://svn.boost.org/trac/boost/ticket/12286 Trac #12319: ['"boost::container::flat_set` should be nothrow move constructible"]]. + +* Revised noexcept expressions of default and move constructors in all containers. [endsect] diff --git a/include/boost/container/deque.hpp b/include/boost/container/deque.hpp index 323de73..63ea2e7 100644 --- a/include/boost/container/deque.hpp +++ b/include/boost/container/deque.hpp @@ -535,7 +535,7 @@ class deque : protected deque_base //! Throws: If allocator_type's default constructor throws. //! //! Complexity: Constant. - deque() + deque() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value) : Base() {} @@ -707,7 +707,7 @@ class deque : protected deque_base //! Throws: If allocator_type's copy constructor throws. //! //! Complexity: Constant. - deque(BOOST_RV_REF(deque) x) + deque(BOOST_RV_REF(deque) x) BOOST_NOEXCEPT_OR_NOTHROW : Base(BOOST_MOVE_BASE(Base, x)) { this->swap_members(x); } diff --git a/include/boost/container/detail/flat_tree.hpp b/include/boost/container/detail/flat_tree.hpp index 4c48c8b..7b540fa 100644 --- a/include/boost/container/detail/flat_tree.hpp +++ b/include/boost/container/detail/flat_tree.hpp @@ -221,6 +221,7 @@ class flat_tree { } flat_tree(BOOST_RV_REF(flat_tree) x) + BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : m_data(boost::move(x.m_data)) { } @@ -269,8 +270,9 @@ class flat_tree { m_data = x.m_data; return *this; } flat_tree& operator=(BOOST_RV_REF(flat_tree) x) - BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value - && boost::container::container_detail::is_nothrow_move_assignable::value ) + BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || + allocator_traits_type::is_always_equal::value) && + boost::container::container_detail::is_nothrow_move_assignable::value) { m_data = boost::move(x.m_data); return *this; } public: diff --git a/include/boost/container/detail/tree.hpp b/include/boost/container/detail/tree.hpp index 0fd6097..384c1fd 100644 --- a/include/boost/container/detail/tree.hpp +++ b/include/boost/container/detail/tree.hpp @@ -612,6 +612,7 @@ class tree } tree(BOOST_RV_REF(tree) x) + BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : AllocHolder(BOOST_MOVE_BASE(AllocHolder, x), x.value_comp()) {} @@ -669,8 +670,9 @@ class tree } tree& operator=(BOOST_RV_REF(tree) x) - BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value - && boost::container::container_detail::is_nothrow_move_assignable::value ) + BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || + allocator_traits_type::is_always_equal::value) && + boost::container::container_detail::is_nothrow_move_assignable::value) { BOOST_ASSERT(this != &x); NodeAlloc &this_alloc = this->node_alloc(); diff --git a/include/boost/container/flat_map.hpp b/include/boost/container/flat_map.hpp index afd5a52..b02db7e 100644 --- a/include/boost/container/flat_map.hpp +++ b/include/boost/container/flat_map.hpp @@ -183,7 +183,8 @@ class flat_map //! Effects: Default constructs an empty flat_map. //! //! Complexity: Constant. - flat_map() + flat_map() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && + container_detail::is_nothrow_default_constructible::value) : m_flat_tree() { //A type must be std::pair @@ -319,6 +320,7 @@ class flat_map //! //! Postcondition: x is emptied. flat_map(BOOST_RV_REF(flat_map) x) + BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : m_flat_tree(boost::move(x.m_flat_tree)) { //A type must be std::pair @@ -362,8 +364,9 @@ class flat_map //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. flat_map& operator=(BOOST_RV_REF(flat_map) x) - BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value - && boost::container::container_detail::is_nothrow_move_assignable::value ) + BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || + allocator_traits_type::is_always_equal::value) && + boost::container::container_detail::is_nothrow_move_assignable::value) { m_flat_tree = boost::move(x.m_flat_tree); return *this; } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -1208,7 +1211,8 @@ class flat_multimap //! Effects: Default constructs an empty flat_map. //! //! Complexity: Constant. - flat_multimap() + flat_multimap() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && + container_detail::is_nothrow_default_constructible::value) : m_flat_tree() { //A type must be std::pair @@ -1343,6 +1347,7 @@ class flat_multimap //! //! Postcondition: x is emptied. flat_multimap(BOOST_RV_REF(flat_multimap) x) + BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : m_flat_tree(boost::move(x.m_flat_tree)) { //A type must be std::pair @@ -1380,8 +1385,9 @@ class flat_multimap //! //! Complexity: Constant. flat_multimap& operator=(BOOST_RV_REF(flat_multimap) x) - BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value - && boost::container::container_detail::is_nothrow_move_assignable::value ) + BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || + allocator_traits_type::is_always_equal::value) && + boost::container::container_detail::is_nothrow_move_assignable::value) { m_flat_tree = boost::move(x.m_flat_tree); return *this; } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) diff --git a/include/boost/container/flat_set.hpp b/include/boost/container/flat_set.hpp index 5da6419..693b295 100644 --- a/include/boost/container/flat_set.hpp +++ b/include/boost/container/flat_set.hpp @@ -112,7 +112,8 @@ class flat_set //! Effects: Default constructs an empty container. //! //! Complexity: Constant. - explicit flat_set() + explicit flat_set() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && + container_detail::is_nothrow_default_constructible::value) : base_t() {} @@ -220,6 +221,7 @@ class flat_set //! //! Postcondition: x is emptied. flat_set(BOOST_RV_REF(flat_set) x) + BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : base_t(BOOST_MOVE_BASE(base_t, x)) {} @@ -251,8 +253,9 @@ class flat_set //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. flat_set& operator=(BOOST_RV_REF(flat_set) x) - BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value - && boost::container::container_detail::is_nothrow_move_assignable::value ) + BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || + allocator_traits_type::is_always_equal::value) && + boost::container::container_detail::is_nothrow_move_assignable::value) { return static_cast(this->base_t::operator=(BOOST_MOVE_BASE(base_t, x))); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -898,7 +901,8 @@ class flat_multiset typedef typename BOOST_CONTAINER_IMPDEF(base_t::const_reverse_iterator) const_reverse_iterator; //! @copydoc ::boost::container::flat_set::flat_set() - explicit flat_multiset() + explicit flat_multiset() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && + container_detail::is_nothrow_default_constructible::value) : base_t() {} @@ -969,6 +973,7 @@ class flat_multiset //! @copydoc ::boost::container::flat_set::flat_set(flat_set &&) flat_multiset(BOOST_RV_REF(flat_multiset) x) + BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : base_t(boost::move(static_cast(x))) {} @@ -988,8 +993,9 @@ class flat_multiset //! @copydoc ::boost::container::flat_set::operator=(flat_set &&) flat_multiset& operator=(BOOST_RV_REF(flat_multiset) x) - BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value - && boost::container::container_detail::is_nothrow_move_assignable::value ) + BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || + allocator_traits_type::is_always_equal::value) && + boost::container::container_detail::is_nothrow_move_assignable::value) { return static_cast(this->base_t::operator=(BOOST_MOVE_BASE(base_t, x))); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) diff --git a/include/boost/container/list.hpp b/include/boost/container/list.hpp index 8236ff7..dcead90 100644 --- a/include/boost/container/list.hpp +++ b/include/boost/container/list.hpp @@ -188,7 +188,7 @@ class list //! Throws: If allocator_type's default constructor throws. //! //! Complexity: Constant. - list() + list() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value) : AllocHolder() {} @@ -250,7 +250,7 @@ class list //! Throws: If allocator_type's copy constructor throws. //! //! Complexity: Constant. - list(BOOST_RV_REF(list) x) + list(BOOST_RV_REF(list) x) BOOST_NOEXCEPT_OR_NOTHROW : AllocHolder(BOOST_MOVE_BASE(AllocHolder, x)) {} diff --git a/include/boost/container/map.hpp b/include/boost/container/map.hpp index 87cc183..e71cb2d 100644 --- a/include/boost/container/map.hpp +++ b/include/boost/container/map.hpp @@ -132,7 +132,8 @@ class map //! Effects: Default constructs an empty map. //! //! Complexity: Constant. - map() + map() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && + container_detail::is_nothrow_default_constructible::value) : base_t() { //A type must be std::pair @@ -266,6 +267,7 @@ class map //! //! Postcondition: x is emptied. map(BOOST_RV_REF(map) x) + BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : base_t(BOOST_MOVE_BASE(base_t, x)) { //A type must be std::pair @@ -310,9 +312,9 @@ class map //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. map& operator=(BOOST_RV_REF(map) x) - BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value - && boost::container::container_detail::is_nothrow_move_assignable::value ) - + BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || + allocator_traits_type::is_always_equal::value) && + boost::container::container_detail::is_nothrow_move_assignable::value) { return static_cast(this->base_t::operator=(BOOST_MOVE_BASE(base_t, x))); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -957,7 +959,8 @@ class multimap //! Effects: Default constructs an empty multimap. //! //! Complexity: Constant. - multimap() + multimap() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && + container_detail::is_nothrow_default_constructible::value) : base_t() { //A type must be std::pair @@ -1088,6 +1091,7 @@ class multimap //! //! Postcondition: x is emptied. multimap(BOOST_RV_REF(multimap) x) + BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : base_t(BOOST_MOVE_BASE(base_t, x)) { //A type must be std::pair @@ -1126,8 +1130,9 @@ class multimap //! //! Complexity: Constant. multimap& operator=(BOOST_RV_REF(multimap) x) - BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value - && boost::container::container_detail::is_nothrow_move_assignable::value ) + BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || + allocator_traits_type::is_always_equal::value) && + boost::container::container_detail::is_nothrow_move_assignable::value) { return static_cast(this->base_t::operator=(BOOST_MOVE_BASE(base_t, x))); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) diff --git a/include/boost/container/set.hpp b/include/boost/container/set.hpp index ca05cac..36ead84 100644 --- a/include/boost/container/set.hpp +++ b/include/boost/container/set.hpp @@ -110,7 +110,8 @@ class set //! Effects: Default constructs an empty set. //! //! Complexity: Constant. - set() + set() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && + container_detail::is_nothrow_default_constructible::value) : base_t() {} @@ -215,6 +216,7 @@ class set //! //! Postcondition: x is emptied. set(BOOST_RV_REF(set) x) + BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : base_t(BOOST_MOVE_BASE(base_t, x)) {} @@ -248,8 +250,9 @@ class set //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. set& operator=(BOOST_RV_REF(set) x) - BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value - && boost::container::container_detail::is_nothrow_move_assignable::value ) + BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || + allocator_traits_type::is_always_equal::value) && + boost::container::container_detail::is_nothrow_move_assignable::value) { return static_cast(this->base_t::operator=(BOOST_MOVE_BASE(base_t, x))); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) @@ -787,7 +790,8 @@ class multiset ////////////////////////////////////////////// //! @copydoc ::boost::container::set::set() - multiset() + multiset() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value && + container_detail::is_nothrow_default_constructible::value) : base_t() {} @@ -856,6 +860,7 @@ class multiset //! @copydoc ::boost::container::set::set(set &&) multiset(BOOST_RV_REF(multiset) x) + BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : base_t(BOOST_MOVE_BASE(base_t, x)) {} @@ -875,8 +880,9 @@ class multiset //! @copydoc ::boost::container::set::operator=(set &&) multiset& operator=(BOOST_RV_REF(multiset) x) - BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value - && boost::container::container_detail::is_nothrow_move_assignable::value ) + BOOST_NOEXCEPT_IF( (allocator_traits_type::propagate_on_container_move_assignment::value || + allocator_traits_type::is_always_equal::value) && + boost::container::container_detail::is_nothrow_move_assignable::value) { return static_cast(this->base_t::operator=(BOOST_MOVE_BASE(base_t, x))); } #if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) diff --git a/include/boost/container/slist.hpp b/include/boost/container/slist.hpp index 8e7aa20..a69c1d3 100644 --- a/include/boost/container/slist.hpp +++ b/include/boost/container/slist.hpp @@ -216,7 +216,7 @@ class slist //! Throws: If allocator_type's copy constructor throws. //! //! Complexity: Constant. - slist() + slist() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value) : AllocHolder() {} @@ -303,7 +303,7 @@ class slist //! Throws: If allocator_type's copy constructor throws. //! //! Complexity: Constant. - slist(BOOST_RV_REF(slist) x) + slist(BOOST_RV_REF(slist) x) BOOST_NOEXCEPT_OR_NOTHROW : AllocHolder(BOOST_MOVE_BASE(AllocHolder, x)) {} @@ -379,7 +379,7 @@ class slist //! Complexity: Constant if allocator_traits_type:: //! propagate_on_container_move_assignment is true or //! this->get>allocator() == x.get_allocator(). Linear otherwise. - slist& operator= (BOOST_RV_REF(slist) x) + slist& operator=(BOOST_RV_REF(slist) x) BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value || allocator_traits_type::is_always_equal::value) { diff --git a/include/boost/container/small_vector.hpp b/include/boost/container/small_vector.hpp index 9759d2f..de3564a 100644 --- a/include/boost/container/small_vector.hpp +++ b/include/boost/container/small_vector.hpp @@ -504,6 +504,7 @@ class small_vector : public small_vector_base public: BOOST_CONTAINER_FORCEINLINE small_vector() + BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value) : base_type(initial_capacity_t(), internal_capacity()) {} @@ -531,12 +532,12 @@ class small_vector : public small_vector_base : base_type(initial_capacity_t(), internal_capacity()) { this->resize(n, v); } - small_vector(size_type n, const value_type &v, const allocator_type &a) + BOOST_CONTAINER_FORCEINLINE small_vector(size_type n, const value_type &v, const allocator_type &a) : base_type(initial_capacity_t(), internal_capacity(), a) { this->resize(n, v); } template - small_vector(InIt first, InIt last + BOOST_CONTAINER_FORCEINLINE small_vector(InIt first, InIt last BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I typename container_detail::disable_if_c < container_detail::is_convertible::value BOOST_MOVE_I container_detail::nat >::type * = 0) diff --git a/include/boost/container/stable_vector.hpp b/include/boost/container/stable_vector.hpp index a332dbc..fccf766 100644 --- a/include/boost/container/stable_vector.hpp +++ b/include/boost/container/stable_vector.hpp @@ -540,7 +540,7 @@ class stable_vector //! Throws: If allocator_type's default constructor throws. //! //! Complexity: Constant. - stable_vector() + stable_vector() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value) : internal_data(), index() { STABLE_VECTOR_CHECK_INVARIANT; @@ -698,7 +698,7 @@ class stable_vector //! Throws: If allocator_type's copy constructor throws. //! //! Complexity: Constant. - stable_vector(BOOST_RV_REF(stable_vector) x) + stable_vector(BOOST_RV_REF(stable_vector) x) BOOST_NOEXCEPT_OR_NOTHROW : internal_data(boost::move(x.priv_node_alloc())), index(boost::move(x.index)) { this->priv_swap_members(x); diff --git a/include/boost/container/static_vector.hpp b/include/boost/container/static_vector.hpp index a37c165..82f83c4 100644 --- a/include/boost/container/static_vector.hpp +++ b/include/boost/container/static_vector.hpp @@ -276,6 +276,7 @@ public: //! @par Complexity //! Linear O(N). BOOST_CONTAINER_FORCEINLINE static_vector(BOOST_RV_REF(static_vector) other) + BOOST_NOEXCEPT_IF(boost::container::container_detail::is_nothrow_move_constructible::value) : base_t(BOOST_MOVE_BASE(base_t, other)) {} diff --git a/include/boost/container/string.hpp b/include/boost/container/string.hpp index c25512a..1e47aba 100644 --- a/include/boost/container/string.hpp +++ b/include/boost/container/string.hpp @@ -591,7 +591,7 @@ class basic_string //! Effects: Default constructs a basic_string. //! //! Throws: If allocator_type's default constructor throws. - basic_string() + basic_string() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value) : base_t() { this->priv_terminate_string(); } diff --git a/include/boost/container/vector.hpp b/include/boost/container/vector.hpp index 01c9a29..6621efc 100644 --- a/include/boost/container/vector.hpp +++ b/include/boost/container/vector.hpp @@ -792,7 +792,7 @@ class vector //! Throws: Nothing. //! //! Complexity: Constant. - vector() BOOST_NOEXCEPT_OR_NOTHROW + vector() BOOST_NOEXCEPT_IF(container_detail::is_nothrow_default_constructible::value) : m_holder() {} @@ -1103,7 +1103,7 @@ class vector //! this->get>allocator() == x.get_allocator(). Linear otherwise. BOOST_CONTAINER_FORCEINLINE vector& operator=(BOOST_RV_REF(vector) x) BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value - || allocator_traits_type::is_always_equal::value) + || allocator_traits_type::is_always_equal::value) { BOOST_ASSERT(&x != this); this->priv_move_assign(boost::move(x));