mirror of
https://github.com/boostorg/intrusive.git
synced 2026-01-19 04:12:14 +00:00
Fixes #99 ("some intrusive containers are not trivially destructible when possible")
Enables conditional triviality with C++20 concepts, introducing defaulted destructors and constructors for hooks and containers using `normal_link`.
This commit is contained in:
@@ -3905,6 +3905,19 @@ to be inserted in intrusive containers are allocated using `std::vector` or `std
|
||||
|
||||
[section:release_notes Release Notes]
|
||||
|
||||
[section:release_notes_boost_1_91_00 Boost 1.91 Release]
|
||||
|
||||
* Hooks and containers using `normal_link`s now have defaulted destructors if C++20 concepts are available. This allows
|
||||
trivially destructible hooks and containers if internally used nodes and comparison objects are trivially destructible.
|
||||
|
||||
* Hooks using `normal_link`s now have defaulted constructors if C++20 concepts are available. This allows
|
||||
trivially default constructible hooks if internally used nodes are trivially destructible.
|
||||
|
||||
* Fixed bugs:
|
||||
* [@https://github.com/boostorg/intrusive/issues/99 GitHub #92: ['some intrusive containers are not trivially destructible when possible]]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:release_notes_boost_1_89_00 Boost 1.89 Release]
|
||||
|
||||
* Fixed bugs:
|
||||
|
||||
@@ -585,6 +585,9 @@ struct bstbase
|
||||
//Detach all inserted nodes. This will add exception safety to bstree_impl
|
||||
//constructors inserting elements.
|
||||
~bstbase()
|
||||
#if defined(BOOST_INTRUSIVE_CONCEPTS_BASED_OVERLOADING)
|
||||
requires (ValueTraits::link_mode != normal_link)
|
||||
#endif
|
||||
{
|
||||
if(is_safe_autounlink<value_traits::link_mode>::value){
|
||||
node_algorithms::clear_and_dispose
|
||||
@@ -594,6 +597,11 @@ struct bstbase
|
||||
node_algorithms::init(this->header_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && defined(BOOST_INTRUSIVE_CONCEPTS_BASED_OVERLOADING)
|
||||
//Default destructor for normal links (allows conditional triviality)
|
||||
~bstbase() requires (ValueTraits::link_mode == normal_link) = default;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -170,12 +170,20 @@ class generic_hook
|
||||
/// @endcond
|
||||
|
||||
inline generic_hook() BOOST_NOEXCEPT
|
||||
#if defined(BOOST_INTRUSIVE_CONCEPTS_BASED_OVERLOADING)
|
||||
requires (LinkMode != normal_link)
|
||||
#endif
|
||||
{
|
||||
if(hooktags::safemode_or_autounlink){
|
||||
node_algorithms::init(this->this_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && defined(BOOST_INTRUSIVE_CONCEPTS_BASED_OVERLOADING)
|
||||
//Default destructor for normal links (allows conditional triviality)
|
||||
generic_hook() requires (LinkMode == normal_link) = default;
|
||||
#endif
|
||||
|
||||
inline generic_hook(const generic_hook& ) BOOST_NOEXCEPT
|
||||
{
|
||||
if(hooktags::safemode_or_autounlink){
|
||||
@@ -187,11 +195,19 @@ class generic_hook
|
||||
{ return *this; }
|
||||
|
||||
inline ~generic_hook()
|
||||
#if defined(BOOST_INTRUSIVE_CONCEPTS_BASED_OVERLOADING)
|
||||
requires (LinkMode != normal_link)
|
||||
#endif
|
||||
{
|
||||
destructor_impl
|
||||
(*this, detail::link_dispatch<hooktags::link_mode>());
|
||||
}
|
||||
|
||||
#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && defined(BOOST_INTRUSIVE_CONCEPTS_BASED_OVERLOADING)
|
||||
//Default destructor for normal links (allows conditional triviality)
|
||||
~generic_hook() requires (LinkMode == normal_link) = default;
|
||||
#endif
|
||||
|
||||
inline void swap_nodes(generic_hook &other) BOOST_NOEXCEPT
|
||||
{
|
||||
node_algorithms::swap_nodes
|
||||
|
||||
@@ -121,5 +121,8 @@ template<unsigned> struct static_assert_test {};
|
||||
# define BOOST_INTRUSIVE_NO_DANGLING
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_concepts) && (__cpp_concepts >= 202002L)
|
||||
# define BOOST_INTRUSIVE_CONCEPTS_BASED_OVERLOADING
|
||||
#endif
|
||||
|
||||
#endif //#ifndef BOOST_INTRUSIVE_DETAIL_WORKAROUND_HPP
|
||||
|
||||
@@ -1909,7 +1909,19 @@ struct hashdata_internal
|
||||
{ return this->priv_size_traits(); }
|
||||
|
||||
~hashdata_internal()
|
||||
{ this->priv_clear_buckets(); }
|
||||
#if defined(BOOST_INTRUSIVE_CONCEPTS_BASED_OVERLOADING)
|
||||
requires (ValueTraits::link_mode != normal_link)
|
||||
#endif
|
||||
{
|
||||
BOOST_IF_CONSTEXPR(safemode_or_autounlink){
|
||||
this->priv_clear_buckets();
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && defined(BOOST_INTRUSIVE_CONCEPTS_BASED_OVERLOADING)
|
||||
//Default destructor for normal links (allows conditional triviality)
|
||||
~hashdata_internal() requires (ValueTraits::link_mode == normal_link) = default;
|
||||
#endif
|
||||
|
||||
using split_bucket_hash_equal_t::priv_clear_buckets;
|
||||
|
||||
@@ -2462,6 +2474,7 @@ class hashtable_impl
|
||||
hashtable_impl& operator=(BOOST_RV_REF(hashtable_impl) x)
|
||||
{ this->swap(x); return *this; }
|
||||
|
||||
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
|
||||
//! <b>Effects</b>: Detaches all elements from this. The objects in the unordered_set
|
||||
//! are not deleted (i.e. no destructors are called).
|
||||
//!
|
||||
@@ -2469,10 +2482,8 @@ class hashtable_impl
|
||||
//! it's a safe-mode or auto-unlink value. Otherwise constant.
|
||||
//!
|
||||
//! <b>Throws</b>: Nothing.
|
||||
~hashtable_impl()
|
||||
{}
|
||||
~hashtable_impl();
|
||||
|
||||
#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
|
||||
//! <b>Effects</b>: Returns an iterator pointing to the beginning of the unordered_set.
|
||||
//!
|
||||
//! <b>Complexity</b>: Amortized constant time.
|
||||
|
||||
@@ -249,6 +249,9 @@ class list_impl
|
||||
//! <b>Complexity</b>: Linear to the number of elements in the list, if
|
||||
//! it's a safe-mode or auto-unlink value . Otherwise constant.
|
||||
~list_impl()
|
||||
#if defined(BOOST_INTRUSIVE_CONCEPTS_BASED_OVERLOADING)
|
||||
requires (ValueTraits::link_mode != normal_link)
|
||||
#endif
|
||||
{
|
||||
BOOST_IF_CONSTEXPR(is_safe_autounlink<ValueTraits::link_mode>::value){
|
||||
this->clear();
|
||||
@@ -256,6 +259,11 @@ class list_impl
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && defined(BOOST_INTRUSIVE_CONCEPTS_BASED_OVERLOADING)
|
||||
//Default destructor for normal links (allows conditional triviality)
|
||||
~list_impl() requires (ValueTraits::link_mode == normal_link) = default;
|
||||
#endif
|
||||
|
||||
//! <b>Requires</b>: value must be an lvalue.
|
||||
//!
|
||||
//! <b>Effects</b>: Inserts the value in the back of the list.
|
||||
|
||||
@@ -367,6 +367,9 @@ class slist_impl
|
||||
//! <b>Complexity</b>: Linear to the number of elements in the list, if
|
||||
//! it's a safe-mode or auto-unlink value. Otherwise constant.
|
||||
~slist_impl()
|
||||
#if defined(BOOST_INTRUSIVE_CONCEPTS_BASED_OVERLOADING)
|
||||
requires (ValueTraits::link_mode != normal_link)
|
||||
#endif
|
||||
{
|
||||
BOOST_IF_CONSTEXPR(is_safe_autounlink<ValueTraits::link_mode>::value){
|
||||
this->clear();
|
||||
@@ -374,6 +377,11 @@ class slist_impl
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) && defined(BOOST_INTRUSIVE_CONCEPTS_BASED_OVERLOADING)
|
||||
//Default destructor for normal links (allows conditional triviality)
|
||||
~slist_impl() requires (ValueTraits::link_mode == normal_link) = default;
|
||||
#endif
|
||||
|
||||
//! <b>Effects</b>: Erases all the elements of the container.
|
||||
//!
|
||||
//! <b>Throws</b>: Nothing.
|
||||
|
||||
172
test/trivial_destructor_test.cpp
Normal file
172
test/trivial_destructor_test.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Ion Gaztanaga 2025-2025
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
//Conditional triviality is based on destructor overloads based on concepts
|
||||
#if defined(BOOST_INTRUSIVE_CONCEPTS_BASED_OVERLOADING)
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <boost/intrusive/slist.hpp>
|
||||
#include <boost/intrusive/set.hpp>
|
||||
#include <boost/intrusive/unordered_set.hpp>
|
||||
#include <boost/intrusive/splay_set.hpp>
|
||||
#include <boost/intrusive/avl_set.hpp>
|
||||
#include <boost/intrusive/sg_set.hpp>
|
||||
#include <boost/intrusive/treap_set.hpp>
|
||||
#include <boost/intrusive/bs_set.hpp>
|
||||
#include <boost/intrusive/pointer_traits.hpp>
|
||||
#include <boost/intrusive/any_hook.hpp>
|
||||
|
||||
using namespace boost::intrusive;
|
||||
|
||||
typedef list_base_hook
|
||||
< void_pointer<void*>, link_mode<normal_link> > list_base_hook_t;
|
||||
typedef slist_base_hook
|
||||
< void_pointer<void*>, link_mode<normal_link> > slist_base_hook_t;
|
||||
typedef set_base_hook
|
||||
< void_pointer<void*>, link_mode<normal_link> > set_base_hook_t;
|
||||
typedef avl_set_base_hook
|
||||
< void_pointer<void*>, link_mode<normal_link> > avl_base_hook_t;
|
||||
typedef bs_set_base_hook
|
||||
< void_pointer<void*>, link_mode<normal_link> > bs_base_hook_t;
|
||||
typedef unordered_set_base_hook
|
||||
< void_pointer<void*>, link_mode<normal_link> > unordered_base_hook_t;
|
||||
typedef any_base_hook
|
||||
< void_pointer<void*>, link_mode<normal_link> > any_base_hook_t;
|
||||
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<list_base_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<slist_base_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<set_base_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<avl_base_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<bs_base_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<unordered_base_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<any_base_hook_t> ));
|
||||
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_default_constructible_v<list_base_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_default_constructible_v<slist_base_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_default_constructible_v<set_base_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_default_constructible_v<avl_base_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_default_constructible_v<bs_base_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_default_constructible_v<unordered_base_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_default_constructible_v<any_base_hook_t> ));
|
||||
|
||||
typedef list_member_hook
|
||||
< void_pointer<void*>, link_mode<normal_link> > list_member_hook_t;
|
||||
typedef slist_member_hook
|
||||
< void_pointer<void*>, link_mode<normal_link> > slist_member_hook_t;
|
||||
typedef set_member_hook
|
||||
< void_pointer<void*>, link_mode<normal_link> > set_member_hook_t;
|
||||
typedef avl_set_member_hook
|
||||
< void_pointer<void*>, link_mode<normal_link> > avl_member_hook_t;
|
||||
typedef bs_set_member_hook
|
||||
< void_pointer<void*>, link_mode<normal_link> > bs_member_hook_t;
|
||||
typedef unordered_set_member_hook
|
||||
< void_pointer<void*>, link_mode<normal_link> > unordered_member_hook_t;
|
||||
typedef any_member_hook
|
||||
< void_pointer<void*>, link_mode<normal_link> > any_member_hook_t;
|
||||
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<list_member_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<slist_member_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<set_member_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<avl_member_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<bs_member_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<unordered_member_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<any_member_hook_t> ));
|
||||
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_default_constructible_v<list_member_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_default_constructible_v<slist_member_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_default_constructible_v<set_member_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_default_constructible_v<avl_member_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_default_constructible_v<bs_member_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_default_constructible_v<unordered_member_hook_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_default_constructible_v<any_member_hook_t> ));
|
||||
|
||||
struct MyType
|
||||
: public list_base_hook_t
|
||||
, public slist_base_hook_t
|
||||
, public set_base_hook_t
|
||||
, public avl_base_hook_t
|
||||
, public bs_base_hook_t
|
||||
, public unordered_base_hook_t
|
||||
, public any_base_hook_t
|
||||
{
|
||||
list_member_hook_t limh;
|
||||
slist_member_hook_t slmh;
|
||||
set_member_hook_t semh;
|
||||
avl_member_hook_t avmh;
|
||||
bs_member_hook_t bsmh;
|
||||
unordered_member_hook_t unmh;
|
||||
any_member_hook_t anmh;
|
||||
|
||||
friend bool operator<(const MyType &, const MyType &) { return true; }
|
||||
friend std::size_t hash_value(const MyType &, const MyType &) { return 0u; }
|
||||
};
|
||||
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<MyType> ));
|
||||
|
||||
typedef list<MyType> list_t;
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<list_t> ));
|
||||
|
||||
typedef slist<MyType> slist_t;
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<slist_t> ));
|
||||
|
||||
typedef set<MyType> set_t;
|
||||
typedef multiset<MyType> multiset_t;
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<set_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<multiset_t> ));
|
||||
|
||||
typedef avl_set<MyType> avl_set_t;
|
||||
typedef avl_multiset<MyType> avl_multiset_t;
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<avl_set_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<avl_multiset_t> ));
|
||||
|
||||
typedef bs_set<MyType> bs_set_t;
|
||||
typedef bs_multiset<MyType> bs_multiset_t;
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<bs_set_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<bs_multiset_t> ));
|
||||
|
||||
typedef sg_set<MyType> sg_set_t;
|
||||
typedef sg_multiset<MyType> sg_multiset_t;
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<sg_set_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<sg_multiset_t> ));
|
||||
|
||||
typedef treap_set<MyType> treap_set_t;
|
||||
typedef treap_multiset<MyType> treap_multiset_t;
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<treap_set_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<treap_multiset_t> ));
|
||||
|
||||
typedef treap_set<MyType> treap_set_t;
|
||||
typedef treap_multiset<MyType> treap_multiset_t;
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<treap_set_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<treap_multiset_t> ));
|
||||
|
||||
typedef unordered_set<MyType> unordered_set_t;
|
||||
typedef unordered_multiset<MyType> unordered_multiset_t;
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<unordered_set_t> ));
|
||||
BOOST_INTRUSIVE_STATIC_ASSERT(( std::is_trivially_destructible_v<unordered_multiset_t> ));
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user