diff --git a/doc/intrusive.qbk b/doc/intrusive.qbk index 5eafab2..4b2c898 100644 --- a/doc/intrusive.qbk +++ b/doc/intrusive.qbk @@ -3798,6 +3798,7 @@ to be inserted in intrusive containers are allocated using `std::vector` or `std * [@https://svn.boost.org/trac/boost/ticket/8468 #8468: Compile error on visual studio 2010/2012 using vector with custom allocator and aligned types] * [@https://svn.boost.org/trac/boost/ticket/9332 #9332: ['"has_member_function_callable_with.hpp compile error on msvc-12.0"]]. * [@https://svn.boost.org/trac/boost/ticket/9746 #9746: Modern Sun CC compiler detects error in intrusive library header] + * [@https://svn.boost.org/trac/boost/ticket/9940 #9940: bad bug in intrusive list with safe_link (or auto_unlink) hooks] * Optimized tree rebalancing code to avoid redundant assignments. diff --git a/include/boost/intrusive/bstree.hpp b/include/boost/intrusive/bstree.hpp index ecd3999..d2850e9 100644 --- a/include/boost/intrusive/bstree.hpp +++ b/include/boost/intrusive/bstree.hpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -557,7 +556,6 @@ template { - template friend class detail::clear_on_destructor_base; public: /// @cond typedef bstbase data_type; @@ -618,7 +616,7 @@ class bstree_impl //! //! Throws: If value_traits::node_traits::node //! constructor throws (this does not happen with predefined Boost.Intrusive hooks) - //! or the copy constructorof the value_compare object throws. Basic guarantee. + //! or the copy constructor of the value_compare object throws. Basic guarantee. explicit bstree_impl( const value_compare &cmp = value_compare() , const value_traits &v_traits = value_traits()) : data_type(cmp, v_traits) @@ -642,6 +640,7 @@ class bstree_impl , const value_traits &v_traits = value_traits()) : data_type(cmp, v_traits) { + //bstbase releases elements in case of exceptions if(unique) this->insert_unique(b, e); else diff --git a/include/boost/intrusive/detail/clear_on_destructor_base.hpp b/include/boost/intrusive/detail/clear_on_destructor_base.hpp deleted file mode 100644 index 164fe40..0000000 --- a/include/boost/intrusive/detail/clear_on_destructor_base.hpp +++ /dev/null @@ -1,40 +0,0 @@ -//////} // /////////////////////////////////////////////////////////////////////// -// -// (C) Copyright Ion Gaztanaga 2008-2013. 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/intrusive for documentation. -// -///////////////////////////////////////////////////////////////////////////// - -#ifndef BOOST_INTRUSIVE_DETAIL_CLEAR_ON_DESTRUCTOR_HPP -#define BOOST_INTRUSIVE_DETAIL_CLEAR_ON_DESTRUCTOR_HPP - -#include - -namespace boost { -namespace intrusive { -namespace detail { - -template -class clear_on_destructor_base -{ - protected: - ~clear_on_destructor_base() - { - static_cast(this)->clear(); - } -}; - -template -class clear_on_destructor_base -{}; - -} // namespace detail { -} // namespace intrusive { -} // namespace boost { - -#include - -#endif //#ifndef BOOST_INTRUSIVE_DETAIL_CLEAR_ON_DESTRUCTOR_HPP diff --git a/include/boost/intrusive/hashtable.hpp b/include/boost/intrusive/hashtable.hpp index db73002..bbf4b70 100644 --- a/include/boost/intrusive/hashtable.hpp +++ b/include/boost/intrusive/hashtable.hpp @@ -510,7 +510,7 @@ struct bucket_plus_vtraits : public ValueTraits typedef typename detail::get_slist_impl_from_supposed_value_traits ::type slist_impl; - typedef typename value_traits::node_traits node_traits; + typedef typename value_traits::node_traits node_traits; typedef unordered_group_adapter group_traits; typedef typename slist_impl::iterator siterator; typedef typename slist_impl::size_type size_type; @@ -532,6 +532,8 @@ struct bucket_plus_vtraits : public ValueTraits ::type const_bucket_value_traits_ptr; typedef typename detail::unordered_bucket_ptr_impl ::type bucket_ptr; + typedef detail::bool_::value> optimize_multikey_t; template bucket_plus_vtraits(const ValueTraits &val_traits, BOOST_FWD_REF(BucketTraitsType) b_traits) @@ -684,6 +686,20 @@ struct bucket_plus_vtraits : public ValueTraits const value_type &priv_value_from_slist_node(slist_node_ptr n) const { return *this->priv_value_traits().to_value_ptr(detail::dcast_bucket_ptr(n)); } + void priv_clear_buckets(const bucket_ptr buckets_ptr, const size_type bucket_cnt) + { + bucket_ptr buckets_it = buckets_ptr; + for(size_type bucket_i = 0; bucket_i != bucket_cnt; ++buckets_it, ++bucket_i){ + if(safemode_or_autounlink){ + bucket_plus_vtraits::priv_clear_group_nodes(*buckets_it, optimize_multikey_t()); + buckets_it->clear_and_dispose(detail::init_disposer()); + } + else{ + buckets_it->clear(); + } + } + } + bucket_traits bucket_traits_; }; @@ -943,6 +959,32 @@ struct hashdata_internal const split_traits &priv_split_traits() const { return *this; } + ~hashdata_internal() + { this->priv_clear_buckets(); } + + void priv_clear_buckets() + { + this->internal.internal.internal.priv_clear_buckets + ( this->internal.priv_get_cache() + , this->internal.internal.internal.priv_bucket_count() + - (this->internal.priv_get_cache() + - this->internal.internal.internal.priv_bucket_pointer())); + } + + void priv_clear_buckets_and_cache() + { + this->priv_clear_buckets(); + this->internal.priv_initialize_cache(); + } + + void priv_initialize_buckets_and_cache() + { + this->internal.internal.internal.priv_clear_buckets + ( this->internal.internal.internal.priv_bucket_pointer() + , this->internal.internal.internal.priv_bucket_count()); + this->internal.priv_initialize_cache(); + } + internal_type internal; //2 }; @@ -1021,18 +1063,15 @@ template template #endif class hashtable_impl - : private detail::clear_on_destructor_base - < hashtable_impl - , true //To always clear the bucket array - //is_safe_autounlink::type::link_mode>::value - > + : private hashtable_data_t + < SizeType + , BoolFlags & hashtable_data_bool_flags_mask + , VoidOrKeyHash, VoidOrKeyEqual, ValueTraits, BucketTraits> { - template friend class detail::clear_on_destructor_base; typedef hashtable_data_t < SizeType , BoolFlags & hashtable_data_bool_flags_mask - , VoidOrKeyHash, VoidOrKeyEqual, ValueTraits, BucketTraits> data_type; - data_type data; + , VoidOrKeyHash, VoidOrKeyEqual, ValueTraits, BucketTraits> data_type; public: typedef ValueTraits value_traits; @@ -1174,9 +1213,9 @@ class hashtable_impl , const hasher & hash_func = hasher() , const key_equal &equal_func = key_equal() , const value_traits &v_traits = value_traits()) - : data(b_traits, hash_func, equal_func, v_traits) + : data_type(b_traits, hash_func, equal_func, v_traits) { - this->priv_initialize_buckets(); + this->data_type::internal.priv_initialize_buckets_and_cache(); this->priv_size_traits().set_size(size_type(0)); size_type bucket_sz = this->priv_bucket_count(); BOOST_INTRUSIVE_INVARIANT_ASSERT(bucket_sz != 0); @@ -1189,7 +1228,7 @@ class hashtable_impl //! Effects: to-do //! hashtable_impl(BOOST_RV_REF(hashtable_impl) x) - : data( ::boost::move(x.priv_bucket_traits()) + : data_type( ::boost::move(x.priv_bucket_traits()) , ::boost::move(x.priv_hasher()) , ::boost::move(x.priv_equal()) , ::boost::move(x.priv_value_traits()) @@ -1221,8 +1260,7 @@ class hashtable_impl //! it's a safe-mode or auto-unlink value. Otherwise constant. //! //! Throws: Nothing. - ~hashtable_impl() - {} + ~hashtable_impl(); #endif //! Effects: Returns an iterator pointing to the beginning of the unordered_set. @@ -1863,7 +1901,7 @@ class hashtable_impl //! to the erased elements. No destructors are called. void clear() { - this->priv_clear_buckets(); + this->data_type::internal.priv_clear_buckets_and_cache(); this->priv_size_traits().set_size(size_type(0)); } @@ -2606,102 +2644,101 @@ class hashtable_impl bound -= (bound != primes); return size_type(*bound); } - /// @cond private: size_traits &priv_size_traits() - { return this->data; } + { return static_cast(static_cast(*this)); } const size_traits &priv_size_traits() const - { return this->data; } + { return static_cast(static_cast(*this)); } bucket_ptr priv_bucket_pointer() const - { return this->data.internal.internal.internal.internal.priv_bucket_pointer(); } + { return this->data_type::internal.internal.internal.internal.priv_bucket_pointer(); } SizeType priv_bucket_count() const - { return this->data.internal.internal.internal.internal.priv_bucket_count(); } + { return this->data_type::internal.internal.internal.internal.priv_bucket_count(); } const bucket_plus_vtraits &get_bucket_value_traits() const - { return this->data.internal.internal.internal.internal.get_bucket_value_traits(); } + { return this->data_type::internal.internal.internal.internal.get_bucket_value_traits(); } bucket_plus_vtraits &get_bucket_value_traits() - { return this->data.internal.internal.internal.internal.get_bucket_value_traits(); } + { return this->data_type::internal.internal.internal.internal.get_bucket_value_traits(); } bucket_traits &priv_bucket_traits() - { return this->data.internal.internal.internal.internal.priv_bucket_traits(); } + { return this->data_type::internal.internal.internal.internal.priv_bucket_traits(); } const bucket_traits &priv_bucket_traits() const - { return this->data.internal.internal.internal.internal.priv_bucket_traits(); } + { return this->data_type::internal.internal.internal.internal.priv_bucket_traits(); } value_traits &priv_value_traits() - { return this->data.internal.internal.internal.internal.priv_value_traits(); } + { return this->data_type::internal.internal.internal.internal.priv_value_traits(); } const value_traits &priv_value_traits() const - { return this->data.internal.internal.internal.internal.priv_value_traits(); } + { return this->data_type::internal.internal.internal.internal.priv_value_traits(); } const_value_traits_ptr value_traits_ptr() const - { return this->data.internal.internal.internal.internal.value_traits_ptr(); } + { return this->data_type::internal.internal.internal.internal.value_traits_ptr(); } siterator priv_invalid_local_it() const - { return this->data.internal.internal.internal.internal.priv_invalid_local_it(); } + { return this->data_type::internal.internal.internal.internal.priv_invalid_local_it(); } split_traits &priv_split_traits() - { return this->data.internal.priv_split_traits(); } + { return this->data_type::internal.priv_split_traits(); } const split_traits &priv_split_traits() const - { return this->data.internal.priv_split_traits(); } + { return this->data_type::internal.priv_split_traits(); } bucket_ptr priv_get_cache() - { return this->data.internal.internal.priv_get_cache(); } + { return this->data_type::internal.internal.priv_get_cache(); } void priv_initialize_cache() - { return this->data.internal.internal.priv_initialize_cache(); } + { return this->data_type::internal.internal.priv_initialize_cache(); } siterator priv_begin() const - { return this->data.internal.internal.priv_begin(); } + { return this->data_type::internal.internal.priv_begin(); } const value_equal &priv_equal() const - { return this->data.internal.internal.priv_equal(); } + { return this->data_type::internal.internal.priv_equal(); } value_equal &priv_equal() - { return this->data.internal.internal.priv_equal(); } + { return this->data_type::internal.internal.priv_equal(); } const hasher &priv_hasher() const - { return this->data.internal.internal.internal.priv_hasher(); } + { return this->data_type::internal.internal.internal.priv_hasher(); } hasher &priv_hasher() - { return this->data.internal.internal.internal.priv_hasher(); } + { return this->data_type::internal.internal.internal.priv_hasher(); } void priv_swap_cache(hashtable_impl &h) - { this->data.internal.internal.priv_swap_cache(h.data.internal.internal); } + { this->data_type::internal.internal.priv_swap_cache(h.data_type::internal.internal); } node &priv_value_to_node(value_type &v) - { return this->data.internal.internal.internal.internal.priv_value_to_node(v); } + { return this->data_type::internal.internal.internal.internal.priv_value_to_node(v); } const node &priv_value_to_node(const value_type &v) const - { return this->data.internal.internal.internal.internal.priv_value_to_node(v); } + { return this->data_type::internal.internal.internal.internal.priv_value_to_node(v); } SizeType priv_get_cache_bucket_num() - { return this->data.internal.internal.priv_get_cache_bucket_num(); } + { return this->data_type::internal.internal.priv_get_cache_bucket_num(); } void priv_insertion_update_cache(SizeType n) - { return this->data.internal.internal.priv_insertion_update_cache(n); } + { return this->data_type::internal.internal.priv_insertion_update_cache(n); } template std::size_t priv_stored_or_compute_hash(const value_type &v, detail::bool_ b) const - { return this->data.internal.internal.internal.priv_stored_or_compute_hash(v, b); } + { return this->data_type::internal.internal.internal.priv_stored_or_compute_hash(v, b); } value_type &priv_value_from_slist_node(slist_node_ptr n) - { return this->data.internal.internal.internal.internal.priv_value_from_slist_node(n); } + { return this->data_type::internal.internal.internal.internal.priv_value_from_slist_node(n); } const value_type &priv_value_from_slist_node(slist_node_ptr n) const - { return this->data.internal.internal.internal.internal.priv_value_from_slist_node(n); } + { return this->data_type::internal.internal.internal.internal.priv_value_from_slist_node(n); } void priv_erasure_update_cache_range(SizeType first_bucket_num, SizeType last_bucket_num) - { return this->data.internal.internal.priv_erasure_update_cache_range(first_bucket_num, last_bucket_num); } + { return this->data_type::internal.internal.priv_erasure_update_cache_range(first_bucket_num, last_bucket_num); } void priv_erasure_update_cache() - { return this->data.internal.internal.priv_erasure_update_cache(); } + { return this->data_type::internal.internal.priv_erasure_update_cache(); } static std::size_t priv_stored_hash(slist_node_ptr n, detail::true_ true_value) { return bucket_plus_vtraits::priv_stored_hash(n, true_value); } @@ -2709,31 +2746,6 @@ class hashtable_impl static std::size_t priv_stored_hash(slist_node_ptr n, detail::false_ false_value) { return bucket_plus_vtraits::priv_stored_hash(n, false_value); } - void priv_clear_buckets(const bucket_ptr buckets_ptr, const size_type bucket_cnt) - { - bucket_ptr buckets_it = buckets_ptr; - for(size_type bucket_i = 0; bucket_i != bucket_cnt; ++buckets_it, ++bucket_i){ - if(safemode_or_autounlink){ - bucket_plus_vtraits_t::priv_clear_group_nodes(*buckets_it, optimize_multikey_t()); - buckets_it->clear_and_dispose(detail::init_disposer()); - } - else{ - buckets_it->clear(); - } - } - this->priv_initialize_cache(); - } - - void priv_initialize_buckets() - { this->priv_clear_buckets(this->priv_bucket_pointer(), this->priv_bucket_count()); } - - void priv_clear_buckets() - { - this->priv_clear_buckets - ( this->priv_get_cache() - , this->priv_bucket_count() - (this->priv_get_cache() - this->priv_bucket_pointer())); - } - std::size_t priv_hash_to_bucket(std::size_t hash_value) const { return detail::hash_to_bucket_split @@ -2815,7 +2827,7 @@ class hashtable_impl } std::size_t priv_get_bucket_num_hash_dispatch(siterator it, detail::false_) //NO store_hash - { return this->data.internal.internal.internal.internal.priv_get_bucket_num_no_hash_store(it, optimize_multikey_t()); } + { return this->data_type::internal.internal.internal.internal.priv_get_bucket_num_no_hash_store(it, optimize_multikey_t()); } static siterator priv_get_previous(bucket_type &b, siterator i) { return bucket_plus_vtraits_t::priv_get_previous(b, i, optimize_multikey_t()); } diff --git a/include/boost/intrusive/list.hpp b/include/boost/intrusive/list.hpp index 01e0b49..ac845c4 100644 --- a/include/boost/intrusive/list.hpp +++ b/include/boost/intrusive/list.hpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -63,12 +62,7 @@ template template #endif class list_impl - : private detail::clear_on_destructor_base - < list_impl - , is_safe_autounlink::value - > { - template friend class detail::clear_on_destructor_base; //Public typedefs public: typedef ValueTraits value_traits; @@ -175,8 +169,10 @@ class list_impl list_impl(Iterator b, Iterator e, const value_traits &v_traits = value_traits()) : data_(v_traits) { + //nothrow, no need to rollback to release elements on exception this->priv_size_traits().set_size(size_type(0)); node_algorithms::init_header(this->get_root_node()); + //nothrow, no need to rollback to release elements on exception this->insert(this->cend(), b, e); } @@ -187,6 +183,7 @@ class list_impl { this->priv_size_traits().set_size(size_type(0)); node_algorithms::init_header(this->get_root_node()); + //nothrow, no need to rollback to release elements on exception this->swap(x); } @@ -195,7 +192,6 @@ class list_impl list_impl& operator=(BOOST_RV_REF(list_impl) x) { this->swap(x); return *this; } - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED //! Effects: If it's not a safe-mode or an auto-unlink value_type //! the destructor does nothing //! (ie. no code is generated). Otherwise it detaches all elements from this. @@ -206,8 +202,11 @@ class list_impl //! Complexity: Linear to the number of elements in the list, if //! it's a safe-mode or auto-unlink value . Otherwise constant. ~list_impl() - {} - #endif + { + if(is_safe_autounlink::value){ + this->clear(); + } + } //! Requires: value must be an lvalue. //! diff --git a/include/boost/intrusive/slist.hpp b/include/boost/intrusive/slist.hpp index 23c7824..fa88cd2 100644 --- a/include/boost/intrusive/slist.hpp +++ b/include/boost/intrusive/slist.hpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -99,12 +98,7 @@ template template #endif class slist_impl - : private detail::clear_on_destructor_base - < slist_impl - , is_safe_autounlink::value - > { - template friend class detail::clear_on_destructor_base; //Public typedefs public: typedef ValueTraits value_traits; @@ -312,6 +306,7 @@ class slist_impl : data_(v_traits) { this->set_default_constructed_state(); + //nothrow, no need to rollback to release elements on exception this->insert_after(this->cbefore_begin(), b, e); } @@ -322,6 +317,7 @@ class slist_impl { this->priv_size_traits().set_size(size_type(0)); node_algorithms::init_header(this->get_root_node()); + //nothrow, no need to rollback to release elements on exception this->swap(x); } @@ -330,7 +326,6 @@ class slist_impl slist_impl& operator=(BOOST_RV_REF(slist_impl) x) { this->swap(x); return *this; } - #ifdef BOOST_INTRUSIVE_DOXYGEN_INVOKED //! Effects: If it's a safe-mode //! or auto-unlink value, the destructor does nothing //! (ie. no code is generated). Otherwise it detaches all elements from this. @@ -341,8 +336,11 @@ class slist_impl //! Complexity: Linear to the number of elements in the list, if //! it's a safe-mode or auto-unlink value. Otherwise constant. ~slist_impl() - {} - #endif + { + if(is_safe_autounlink::value){ + this->clear(); + } + } //! Effects: Erases all the elements of the container. //!