Adds uses-allocator-construction (for types where boost::container::uses_allocator<T>::value == true), in the following utilities:

- Segment managers in their `construct` methods
- Allocators
This commit is contained in:
Ion Gaztañaga
2025-11-30 23:56:24 +01:00
parent fe4e89d6d5
commit 156f5afaa7
12 changed files with 292 additions and 55 deletions

View File

@@ -6785,6 +6785,10 @@ thank them:
[section:release_notes_boost_1_91_00 Boost 1.91 Release]
* Adds uses-allocator-construction (for types where `boost::container::uses_allocator<T>::value == true`), in the following utilities:
* Segment managers in their `construct` methods
* Allocators
* Fixed bugs:
* [@https://github.com/boostorg/interprocess/issues/247 GitHub #247 (['"destruction of move-constructed map using private_adaptive_pool triggers Assertion"])].

View File

@@ -0,0 +1,115 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-2012. 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/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/interprocess/detail/workaround.hpp>
//[doc_complex_map_uses_allocator
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/container/map.hpp>
#include <boost/container/vector.hpp>
#include <boost/container/string.hpp>
//<-
#include "../test/get_process_id_name.hpp"
//->
using namespace boost::interprocess;
//Typedefs of allocators and containers
typedef managed_shared_memory::segment_manager segment_manager_t;
typedef allocator<void, segment_manager_t> void_allocator;
typedef allocator<int, segment_manager_t> int_allocator;
typedef boost::container::vector<int, int_allocator> int_vector;
typedef allocator<int_vector, segment_manager_t> int_vector_allocator;
typedef boost::container::vector<int_vector, int_vector_allocator> int_vector_vector;
typedef allocator<char, segment_manager_t> char_allocator;
typedef boost::container::basic_string<char, std::char_traits<char>, char_allocator> char_string;
class complex_data
{
int id_;
char_string char_string_;
int_vector_vector int_vector_vector_;
public:
//Mark this class as uses-allocator construction-ready (see Boost.Container's docs)
//Boost.Interprocess machinery will pass the allocator argument automatically if
//constructors takes the allocator_type as the last argument of constructors
typedef void_allocator allocator_type;
//Since void_allocator is convertible to any other allocator<T>, we can simplify
//the initialization taking just one allocator for all inner containers.
complex_data(int id, const char *name, const void_allocator &void_alloc)
: id_(id), char_string_(name, void_alloc), int_vector_vector_(void_alloc)
{}
//Other members...
//<-
int get_id() { return id_; };
char_string get_char_string() { return char_string_; };
int_vector_vector get_int_vector_vector() { return int_vector_vector_; };
//->
};
//A transparent comparison functor
//Allows creating associative container `value_type`s from comparable
//types (e.g. shared memory string types from "const char *" arguments)
struct less_transparent
{
typedef void is_transparent;
template<class T, class U>
bool operator() (const T &t, const U &u) const
{ return t < u; }
};
//Definition of the map holding a string as key and complex_data as mapped type
typedef std::pair<const char_string, complex_data> map_value_type;
typedef std::pair<char_string, complex_data> movable_to_map_value_type;
typedef allocator<map_value_type, segment_manager_t> map_value_type_allocator;
typedef boost::container::map< char_string, complex_data
, less_transparent, map_value_type_allocator> complex_map_type;
int main ()
{
//Remove shared memory on construction and destruction
struct shm_remove
{
shm_remove() { shared_memory_object::remove(test::get_process_id_name()); }
~shm_remove(){ shared_memory_object::remove(test::get_process_id_name()); }
} remover;
//<-
(void)remover;
//->
//Create shared memory
managed_shared_memory segment(create_only, test::get_process_id_name(), 65536);
//Construct the shared memory map (associated with name "MyMap") and fill it using "extended uses allocator construction".
//In this case "construct" tries to automatically pass the allocator argument to the constructed
//type in addition to user-supplied arguments. "Uses-allocator construction" from the C++ standard
//
//In this case, no user arguments are provided, but the segment manager machinery has
//detected that boost::container::map supports the user-allocator-construction protocol
//so it automatically adds the allocator parameter and calls map::map(allocator_type) constructor.
complex_map_type *mymap = segment.construct<complex_map_type>("MyMap")();
//This transparent insertion function plus uses-allocator construction so that
//the programmer does not need to explicitly pass allocator instances. The container,
//through boost::container::allocator::construct function, automatically adds the needed allocator
//arguments without forcing the user to supply them, calling the following constructors:
//
//key_type --> basic_string(const char *, allocator_type)
//mapped_type --> complex_data(int, const char *, allocator_type)
//
//The programmer only needs to specify the non-allocator arguments
mymap->try_emplace("key_str", 3, "default_name");
return 0;
}
//]

View File

@@ -105,6 +105,7 @@ class adaptive_pool_base
<const value_type>::type const_reference;
typedef typename segment_manager::size_type size_type;
typedef typename segment_manager::difference_type difference_type;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
typedef boost::interprocess::version_type<adaptive_pool_base, Version> version;
typedef boost::container::dtl::transform_multiallocation_chain
@@ -125,6 +126,8 @@ class adaptive_pool_base
adaptive_pool_base& operator=
(const adaptive_pool_base<Version2, T2, SegmentManager2, N2, F2, O2>&);
public:
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
public:
@@ -174,8 +177,8 @@ class adaptive_pool_base
{ return node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))->get_segment_manager(); }
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Requires</b>: Uses-allocator construction of T with allocator
//! `segment_manager*` and constructor arguments `std::forward<Args>(args)...`
//! <b>Requires</b>: Uses-allocator construction of T with allocator argument
//! `uses_segment_manager_t` and additional constructor arguments `std::forward<Args>(args)...`
//! is well-formed. [Note: uses-allocator construction is always well formed for
//! types that do not use allocators. - end note]
//!
@@ -189,7 +192,7 @@ class adaptive_pool_base
{
boost::container::dtl::allocator_traits_dummy<U> atd;
boost::container::dtl::dispatch_uses_allocator
(atd, this->get_segment_manager(), p, ::boost::forward<Args>(args)...);
(atd, uses_segment_manager_t(this->get_segment_manager()), p, ::boost::forward<Args>(args)...);
}
#else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
@@ -200,7 +203,7 @@ class adaptive_pool_base
{\
boost::container::dtl::allocator_traits_dummy<U> atd;\
boost::container::dtl::dispatch_uses_allocator\
(atd, this->get_segment_manager(), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\
(atd, uses_segment_manager_t(this->get_segment_manager()), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\
}\
//
BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_ALLOCATORS_ADAPTIVE_POOL_CONSTRUCT_CODE)
@@ -253,6 +256,8 @@ class adaptive_pool_v1
typedef ipcdetail::adaptive_pool_base
< 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
template<class T2>
struct rebind
{
@@ -263,6 +268,10 @@ class adaptive_pool_v1
: base_t(segment_mngr)
{}
adaptive_pool_v1(uses_segment_manager_t usm)
: base_t(usm.get_segment_manager())
{}
template<class T2>
adaptive_pool_v1
(const adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
@@ -311,7 +320,8 @@ class adaptive_pool
typedef ipcdetail::adaptive_pool_base
< 2, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
public:
typedef boost::interprocess::version_type<adaptive_pool, 2> version;
typedef boost::interprocess::version_type<adaptive_pool, 2> version;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
template<class T2>
struct rebind
@@ -323,6 +333,10 @@ class adaptive_pool
: base_t(segment_mngr)
{}
adaptive_pool(uses_segment_manager_t usm)
: base_t(usm.get_segment_manager())
{}
template<class T2>
adaptive_pool
(const adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
@@ -419,8 +433,8 @@ class adaptive_pool
//!Never throws
const_pointer address(const_reference value) const;
//! <b>Requires</b>: Uses-allocator construction of T with allocator
//! `segment_manager*` and constructor arguments `std::forward<Args>(args)...`
//! <b>Requires</b>: Uses-allocator construction of T with allocator argument
//! `uses_segment_manager_t` and additional constructor arguments `std::forward<Args>(args)...`
//! is well-formed. [Note: uses-allocator construction is always well formed for
//! types that do not use allocators. - end note]
//!

View File

@@ -105,6 +105,7 @@ class allocator
<const value_type>::type const_reference;
typedef typename segment_manager::size_type size_type;
typedef typename segment_manager::difference_type difference_type;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
typedef boost::interprocess::version_type<allocator, 2> version;
@@ -113,6 +114,7 @@ class allocator
//Experimental. Don't use.
typedef boost::container::dtl::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED
//!Obtains an allocator that allocates
@@ -133,6 +135,12 @@ class allocator
allocator(segment_manager *segment_mngr)
: mp_mngr(segment_mngr) { }
//!Constructor that enables uses-allocator
//!Never throws
allocator(uses_segment_manager_t usm)
: mp_mngr(usm.get_segment_manager())
{}
//!Constructor from other allocator.
//!Never throws
allocator(const allocator &other)
@@ -161,8 +169,8 @@ class allocator
{ mp_mngr->deallocate((void*)ipcdetail::to_raw_pointer(ptr)); }
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Requires</b>: Uses-allocator construction of T with allocator
//! `segment_manager*` and constructor arguments `std::forward<Args>(args)...`
//! <b>Requires</b>: Uses-allocator construction of T with allocator argument
//! `uses_segment_manager` and constructor arguments `std::forward<Args>(args)...`
//! is well-formed. [Note: uses-allocator construction is always well formed for
//! types that do not use allocators. - end note]
//!
@@ -176,7 +184,7 @@ class allocator
{
boost::container::dtl::allocator_traits_dummy<U> atd;
boost::container::dtl::dispatch_uses_allocator
(atd, this->get_segment_manager(), p, ::boost::forward<Args>(args)...);
(atd, uses_segment_manager_t(this->get_segment_manager()), p, ::boost::forward<Args>(args)...);
}
#else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
@@ -187,7 +195,7 @@ class allocator
{\
boost::container::dtl::allocator_traits_dummy<U> atd;\
boost::container::dtl::dispatch_uses_allocator\
(atd, this->get_segment_manager(), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\
(atd, uses_segment_manager_t(this->get_segment_manager()), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\
}\
//
BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_ALLOCATORS_ALLOCATOR_CONSTRUCT_CODE)

View File

@@ -72,6 +72,8 @@ class cached_adaptive_pool_v1
>
, 1> base_t;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
template<class T2>
struct rebind
{
@@ -86,6 +88,11 @@ class cached_adaptive_pool_v1
: base_t(segment_mngr, max_cached_nodes)
{}
cached_adaptive_pool_v1(uses_segment_manager_t usm,
size_type max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
: base_t(usm.get_segment_manager(), max_cached_nodes)
{}
template<class T2>
cached_adaptive_pool_v1
(const cached_adaptive_pool_v1
@@ -160,6 +167,7 @@ class cached_adaptive_pool
BOOST_COPYABLE_AND_MOVABLE_ALT(cached_adaptive_pool)
public:
typedef boost::interprocess::version_type<cached_adaptive_pool, 2> version;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
template<class T2>
struct rebind
@@ -173,6 +181,11 @@ class cached_adaptive_pool
: base_t(segment_mngr, max_cached_nodes)
{}
cached_adaptive_pool(uses_segment_manager_t usm,
std::size_t max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
: base_t(usm.get_segment_manager(), max_cached_nodes)
{}
template<class T2>
cached_adaptive_pool
(const cached_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
@@ -281,8 +294,8 @@ class cached_adaptive_pool
//!Never throws
const_pointer address(const_reference value) const;
//! <b>Requires</b>: Uses-allocator construction of T with allocator
//! `segment_manager*` and constructor arguments `std::forward<Args>(args)...`
//! <b>Requires</b>: Uses-allocator construction of T with allocator argument
//! `uses_segment_manager_t` and additional constructor arguments `std::forward<Args>(args)...`
//! is well-formed. [Note: uses-allocator construction is always well formed for
//! types that do not use allocators. - end note]
//!

View File

@@ -69,6 +69,7 @@ class cached_node_allocator_v1
, NodesPerBlock
>
, 1> base_t;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
template<class T2>
struct rebind
@@ -84,6 +85,11 @@ class cached_node_allocator_v1
: base_t(segment_mngr, max_cached_nodes)
{}
cached_node_allocator_v1(uses_segment_manager_t usm,
size_type max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
: base_t(usm.get_segment_manager(), max_cached_nodes)
{}
template<class T2>
cached_node_allocator_v1
(const cached_node_allocator_v1
@@ -135,8 +141,9 @@ class cached_node_allocator
BOOST_COPYABLE_AND_MOVABLE_ALT(cached_node_allocator)
public:
typedef boost::interprocess::version_type<cached_node_allocator, 2> version;
typedef typename base_t::size_type size_type;
typedef boost::interprocess::version_type<cached_node_allocator, 2> version;
typedef typename base_t::size_type size_type;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
template<class T2>
struct rebind
@@ -149,6 +156,11 @@ class cached_node_allocator
: base_t(segment_mngr, max_cached_nodes)
{}
cached_node_allocator(uses_segment_manager_t usm,
size_type max_cached_nodes = base_t::DEFAULT_MAX_CACHED_NODES)
: base_t(usm.get_segment_manager(), max_cached_nodes)
{}
template<class T2>
cached_node_allocator
(const cached_node_allocator<T2, SegmentManager, NodesPerBlock> &other)
@@ -253,8 +265,8 @@ class cached_node_allocator
//!Never throws
pointer address(reference value) const;
//! <b>Requires</b>: Uses-allocator construction of T with allocator
//! `segment_manager*` and constructor arguments `std::forward<Args>(args)...`
//! <b>Requires</b>: Uses-allocator construction of T with allocator argument
//! `uses_segment_manager_t` and additional constructor arguments `std::forward<Args>(args)...`
//! is well-formed. [Note: uses-allocator construction is always well formed for
//! types that do not use allocators. - end note]
//!

View File

@@ -78,6 +78,21 @@ struct sizeof_value<const volatile void>
static const std::size_t value = sizeof(void*);
};
template<class SegmentManager>
class uses_segment_manager
{
private:
SegmentManager *const m_mngr;
public:
explicit uses_segment_manager(SegmentManager *mngr)
: m_mngr(mngr)
{}
SegmentManager *get_segment_manager()
{ return m_mngr; }
};
namespace ipcdetail {
//!Object function that creates the node allocator if it is not created and
@@ -582,6 +597,7 @@ class cached_allocator_impl
typedef typename base_t::size_type size_type;
typedef typename base_t::multiallocation_chain multiallocation_chain;
typedef typename base_t::value_type value_type;
typedef uses_segment_manager<segment_manager> uses_segment_manager_t;
BOOST_COPYABLE_AND_MOVABLE_ALT(cached_allocator_impl)
@@ -621,8 +637,8 @@ class cached_allocator_impl
{ return m_cache.get_segment_manager(); }
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Requires</b>: Uses-allocator construction of T with allocator
//! `segment_manager*` and constructor arguments `std::forward<Args>(args)...`
//! <b>Requires</b>: Uses-allocator construction of T with allocator argument
//! `uses_segment_manager_t` and additional constructor arguments `std::forward<Args>(args)...`
//! is well-formed. [Note: uses-allocator construction is always well formed for
//! types that do not use allocators. - end note]
//!
@@ -636,7 +652,7 @@ class cached_allocator_impl
{
boost::container::dtl::allocator_traits_dummy<U> atd;
boost::container::dtl::dispatch_uses_allocator
(atd, this->get_segment_manager(), p, ::boost::forward<Args>(args)...);
(atd, uses_segment_manager_t(this->get_segment_manager()), p, ::boost::forward<Args>(args)...);
}
#else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
@@ -647,7 +663,7 @@ class cached_allocator_impl
{\
boost::container::dtl::allocator_traits_dummy<U> atd;\
boost::container::dtl::dispatch_uses_allocator\
(atd, this->get_segment_manager(), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\
(atd, uses_segment_manager_t(this->get_segment_manager()), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\
}\
//
BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_ALLOCATORS_ALLOCATOR_COMMON_CONSTRUCT_CODE)

View File

@@ -106,6 +106,7 @@ class node_allocator_base
typedef boost::interprocess::version_type<node_allocator_base, Version> version;
typedef boost::container::dtl::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
//!Obtains node_allocator_base from
//!node_allocator_base
@@ -173,8 +174,8 @@ class node_allocator_base
{ return node_pool<0>::get(ipcdetail::to_raw_pointer(mp_node_pool))->get_segment_manager(); }
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Requires</b>: Uses-allocator construction of T with allocator
//! `segment_manager*` and constructor arguments `std::forward<Args>(args)...`
//! <b>Requires</b>: Uses-allocator construction of T with allocator argument
//! `uses_segment_manager_t` and additional constructor arguments `std::forward<Args>(args)...`
//! is well-formed. [Note: uses-allocator construction is always well formed for
//! types that do not use allocators. - end note]
//!
@@ -188,7 +189,7 @@ class node_allocator_base
{
boost::container::dtl::allocator_traits_dummy<U> atd;
boost::container::dtl::dispatch_uses_allocator
(atd, this->get_segment_manager(), p, ::boost::forward<Args>(args)...);
(atd, uses_segment_manager_t(this->get_segment_manager()), p, ::boost::forward<Args>(args)...);
}
#else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
@@ -199,7 +200,7 @@ class node_allocator_base
{\
boost::container::dtl::allocator_traits_dummy<U> atd;\
boost::container::dtl::dispatch_uses_allocator\
(atd, this->get_segment_manager(), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\
(atd, uses_segment_manager_t(this->get_segment_manager()), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\
}\
//
BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_ALLOCATORS_NODE_ALLOCATOR_CONSTRUCT_CODE)
@@ -258,6 +259,10 @@ class node_allocator_v1
: base_t(segment_mngr)
{}
node_allocator_v1(typename base_t::uses_segment_manager_t usm)
: base_t(usm.get_segment_manager())
{}
template<class T2>
node_allocator_v1
(const node_allocator_v1<T2, SegmentManager, NodesPerBlock> &other)
@@ -308,6 +313,10 @@ class node_allocator
: base_t(segment_mngr)
{}
node_allocator(typename base_t::uses_segment_manager_t usm)
: base_t(usm.get_segment_manager())
{}
template<class T2>
node_allocator
(const node_allocator<T2, SegmentManager, NodesPerBlock> &other)
@@ -404,8 +413,8 @@ class node_allocator
//!Never throws
const_pointer address(const_reference value) const;
//! <b>Requires</b>: Uses-allocator construction of T with allocator
//! `segment_manager*` and constructor arguments `std::forward<Args>(args)...`
//! <b>Requires</b>: Uses-allocator construction of T with allocator argument
//! `uses_segment_manager_t` and additional constructor arguments `std::forward<Args>(args)...`
//! is well-formed. [Note: uses-allocator construction is always well formed for
//! types that do not use allocators. - end note]
//!

View File

@@ -104,6 +104,7 @@ class private_adaptive_pool_base
<private_adaptive_pool_base, Version> version;
typedef boost::container::dtl::transform_multiallocation_chain
<typename SegmentManager::multiallocation_chain, T>multiallocation_chain;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
//!Obtains node_allocator from other node_allocator
template<class T2>
@@ -178,8 +179,8 @@ class private_adaptive_pool_base
{ return m_node_pool.get_segment_manager(); }
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Requires</b>: Uses-allocator construction of T with allocator
//! `segment_manager*` and constructor arguments `std::forward<Args>(args)...`
//! <b>Requires</b>: Uses-allocator construction of T with allocator argument
//! `uses_segment_manager_t` and additional constructor arguments `std::forward<Args>(args)...`
//! is well-formed. [Note: uses-allocator construction is always well formed for
//! types that do not use allocators. - end note]
//!
@@ -193,7 +194,7 @@ class private_adaptive_pool_base
{
boost::container::dtl::allocator_traits_dummy<U> atd;
boost::container::dtl::dispatch_uses_allocator
(atd, this->get_segment_manager(), p, ::boost::forward<Args>(args)...);
(atd, uses_segment_manager_t(this->get_segment_manager()), p, ::boost::forward<Args>(args)...);
}
#else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
@@ -204,7 +205,7 @@ class private_adaptive_pool_base
{\
boost::container::dtl::allocator_traits_dummy<U> atd;\
boost::container::dtl::dispatch_uses_allocator\
(atd, this->get_segment_manager(), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\
(atd, uses_segment_manager_t(this->get_segment_manager()), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\
}\
//
BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_ALLOCATORS_PRIVATE_ADAPTIVE_POOL_CONSTRUCT_CODE)
@@ -260,6 +261,7 @@ class private_adaptive_pool_v1
typedef ipcdetail::private_adaptive_pool_base
< 1, T, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> base_t;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
template<class T2>
struct rebind
{
@@ -270,6 +272,10 @@ class private_adaptive_pool_v1
: base_t(segment_mngr)
{}
private_adaptive_pool_v1(uses_segment_manager_t usm)
: base_t(usm.get_segment_manager())
{}
template<class T2>
private_adaptive_pool_v1
(const private_adaptive_pool_v1<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
@@ -327,7 +333,8 @@ class private_adaptive_pool
BOOST_COPYABLE_AND_MOVABLE_ALT(private_adaptive_pool)
public:
typedef boost::interprocess::version_type<private_adaptive_pool, 2> version;
typedef boost::interprocess::version_type<private_adaptive_pool, 2> version;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
template<class T2>
struct rebind
@@ -340,6 +347,10 @@ class private_adaptive_pool
: base_t(segment_mngr)
{}
private_adaptive_pool(uses_segment_manager_t usm)
: base_t(usm.get_segment_manager())
{}
template<class T2>
private_adaptive_pool
(const private_adaptive_pool<T2, SegmentManager, NodesPerBlock, MaxFreeBlocks, OverheadPercent> &other)
@@ -449,8 +460,8 @@ class private_adaptive_pool
//!Never throws
const_pointer address(const_reference value) const;
//! <b>Requires</b>: Uses-allocator construction of T with allocator
//! `segment_manager*` and constructor arguments `std::forward<Args>(args)...`
//! <b>Requires</b>: Uses-allocator construction of T with allocator argument
//! `uses_segment_manager_t` and additional constructor arguments `std::forward<Args>(args)...`
//! is well-formed. [Note: uses-allocator construction is always well formed for
//! types that do not use allocators. - end note]
//!

View File

@@ -66,6 +66,7 @@ class private_node_allocator_base
//Segment manager
typedef SegmentManager segment_manager;
typedef typename SegmentManager::void_pointer void_pointer;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED)
private:
@@ -168,8 +169,8 @@ class private_node_allocator_base
{ return m_node_pool.get_segment_manager(); }
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//! <b>Requires</b>: Uses-allocator construction of T with allocator
//! `segment_manager*` and constructor arguments `std::forward<Args>(args)...`
//! <b>Requires</b>: Uses-allocator construction of T with allocator argument
//! `uses_segment_manager_t` and additional constructor arguments `std::forward<Args>(args)...`
//! is well-formed. [Note: uses-allocator construction is always well formed for
//! types that do not use allocators. - end note]
//!
@@ -183,7 +184,7 @@ class private_node_allocator_base
{
boost::container::dtl::allocator_traits_dummy<U> atd;
boost::container::dtl::dispatch_uses_allocator
(atd, this->get_segment_manager(), p, ::boost::forward<Args>(args)...);
(atd, uses_segment_manager_t(this->get_segment_manager()), p, ::boost::forward<Args>(args)...);
}
#else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
@@ -194,7 +195,7 @@ class private_node_allocator_base
{\
boost::container::dtl::allocator_traits_dummy<U> atd;\
boost::container::dtl::dispatch_uses_allocator\
(atd, this->get_segment_manager(), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\
(atd, uses_segment_manager_t(this->get_segment_manager()), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\
}\
//
BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_ALLOCATORS_PRIVATE_NODE_ALLOCATOR_CONSTRUCT_CODE)
@@ -245,6 +246,7 @@ class private_node_allocator_v1
public:
typedef ipcdetail::private_node_allocator_base
< 1, T, SegmentManager, NodesPerBlock> base_t;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
template<class T2>
struct rebind
@@ -256,6 +258,10 @@ class private_node_allocator_v1
: base_t(segment_mngr)
{}
private_node_allocator_v1(uses_segment_manager_t usm)
: base_t(usm.get_segment_manager())
{}
template<class T2>
private_node_allocator_v1
(const private_node_allocator_v1<T2, SegmentManager, NodesPerBlock> &other)
@@ -302,7 +308,9 @@ class private_node_allocator
BOOST_COPYABLE_AND_MOVABLE_ALT(private_node_allocator)
public:
typedef boost::interprocess::version_type<private_node_allocator, 2> version;
typedef boost::interprocess::version_type<private_node_allocator, 2> version;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
template<class T2>
struct rebind
@@ -315,6 +323,10 @@ class private_node_allocator
: base_t(segment_mngr)
{}
private_node_allocator(uses_segment_manager_t usm)
: base_t(usm.get_segment_manager())
{}
template<class T2>
private_node_allocator
(const private_node_allocator<T2, SegmentManager, NodesPerBlock> &other)
@@ -424,8 +436,8 @@ class private_node_allocator
//!Never throws
const_pointer address(const_reference value) const;
//! <b>Requires</b>: Uses-allocator construction of T with allocator
//! `segment_manager*` and constructor arguments `std::forward<Args>(args)...`
//! <b>Requires</b>: Uses-allocator construction of T with allocator argument
//! `uses_segment_manager_t` and additional constructor arguments `std::forward<Args>(args)...`
//! is well-formed. [Note: uses-allocator construction is always well formed for
//! types that do not use allocators. - end note]
//!

View File

@@ -32,6 +32,8 @@
#include <boost/interprocess/detail/variadic_templates_tools.hpp>
#endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING
#include <boost/container/detail/placement_new.hpp>
#include <boost/container/detail/dispatch_uses_allocator.hpp>
#include <boost/interprocess/allocators/detail/allocator_common.hpp>
#include <cstddef>
@@ -73,13 +75,14 @@ struct CtorArgN
: args_(args...)
{}
void construct_n(void *mem, std::size_t num)
template<class SegmentManager>
void construct_n(void *mem, SegmentManager *segment_manager, std::size_t num)
{
std::size_t constructed = 0;
BOOST_INTERPROCESS_TRY{
T* memory = static_cast<T*>(mem);
for(constructed = 0; constructed < num; ++constructed){
this->construct(memory++, IsIterator(), index_tuple_t());
this->construct(memory++, segment_manager, IsIterator(), index_tuple_t());
this->do_increment(IsIterator(), index_tuple_t());
}
}
@@ -90,14 +93,26 @@ struct CtorArgN
}
private:
template<std::size_t ...IdxPack>
void construct(void *mem, true_, const index_tuple<IdxPack...>&)
{ ::new((void*)mem, boost_container_new_t()) T(*boost::forward<Args>((get<IdxPack>)(args_))...); }
template<class SegmentManager, std::size_t ...IdxPack>
void construct(void* mem, SegmentManager *segment_manager, true_, const index_tuple<IdxPack...>&)
{
boost::container::dtl::allocator_traits_dummy<T> atd;
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
boost::container::dtl::dispatch_uses_allocator
(atd, uses_segment_manager_t(segment_manager), static_cast<T*>(mem), *boost::forward<Args>((get<IdxPack>)(args_))...);
}
template<std::size_t ...IdxPack>
void construct(void *mem, false_, const index_tuple<IdxPack...>&)
{ ::new((void*)mem, boost_container_new_t()) T(boost::forward<Args>((get<IdxPack>)(args_))...); }
//{ ::new((void*)mem, boost_container_new_t()) T(*boost::forward<Args>((get<IdxPack>)(args_))...); }
template<class SegmentManager, std::size_t ...IdxPack>
void construct(void *mem, SegmentManager *segment_manager, false_, const index_tuple<IdxPack...>&)
{
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;
boost::container::dtl::allocator_traits_dummy<T> atd;
boost::container::dtl::dispatch_uses_allocator
(atd, uses_segment_manager_t(segment_manager), static_cast<T*>(mem), boost::forward<Args>((get<IdxPack>)(args_))...);
}
template<std::size_t ...IdxPack>
void do_increment(true_, const index_tuple<IdxPack...>&)
{
@@ -163,13 +178,17 @@ struct CtorArg##N\
CtorArg##N ( BOOST_MOVE_UREF##N )\
BOOST_MOVE_COLON##N BOOST_MOVE_FWD_INIT##N{}\
\
void construct_n(void *mem, std::size_t num)\
template<class SegmentManager>\
void construct_n(void *mem, SegmentManager *segment_manager, std::size_t num)\
{\
std::size_t constructed = 0;\
BOOST_INTERPROCESS_TRY{\
T* memory = static_cast<T*>(mem);\
for (constructed = 0; constructed < num; ++constructed) {\
::new((void*)memory++) T ( BOOST_MOVE_MFWD##N );\
boost::container::dtl::allocator_traits_dummy<T> atd;\
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;\
boost::container::dtl::dispatch_uses_allocator\
(atd, uses_segment_manager_t(segment_manager), memory++ BOOST_MOVE_I##N BOOST_MOVE_MFWD##N);\
}\
}\
BOOST_INTERPROCESS_CATCH(...) {\
@@ -201,13 +220,17 @@ struct CtorIt##N\
CtorIt##N ( BOOST_MOVE_VAL##N )\
BOOST_MOVE_COLON##N BOOST_MOVE_VAL_INIT##N{}\
\
void construct_n(void *mem, std::size_t num)\
template<class SegmentManager>\
void construct_n(void *mem, SegmentManager *segment_manager, std::size_t num)\
{\
std::size_t constructed = 0;\
BOOST_INTERPROCESS_TRY{\
T* memory = static_cast<T*>(mem);\
for(constructed = 0; constructed < num; ++constructed){\
::new((void*)memory++) T( BOOST_MOVE_MITFWD##N );\
boost::container::dtl::allocator_traits_dummy<T> atd;\
typedef uses_segment_manager<SegmentManager> uses_segment_manager_t;\
boost::container::dtl::dispatch_uses_allocator\
(atd, uses_segment_manager_t(segment_manager), memory++ BOOST_MOVE_I##N BOOST_MOVE_MITFWD##N);\
++(*this);\
}\
}\

View File

@@ -734,7 +734,7 @@ class segment_manager
ptr = hdr->value();
//Now call constructors
pr.construct_n(ptr, num);
pr.construct_n(ptr, this, num);
//All constructors successful, disable rollback
mem.release();
@@ -1109,7 +1109,7 @@ class segment_manager
value_eraser<index_t> v_eraser(index, it);
//Construct array, this can throw
pr.construct_n(ptr, num);
pr.construct_n(ptr, this, num);
//Release rollbacks since construction was successful
v_eraser.release();