diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index db12d70..0d586ca 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -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::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"])]. diff --git a/example/doc_complex_map_uses_allocator.cpp b/example/doc_complex_map_uses_allocator.cpp new file mode 100644 index 0000000..8b09f26 --- /dev/null +++ b/example/doc_complex_map_uses_allocator.cpp @@ -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 +//[doc_complex_map_uses_allocator +#include +#include +#include +#include +#include +//<- +#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_allocator; +typedef allocator int_allocator; +typedef boost::container::vector int_vector; +typedef allocator int_vector_allocator; +typedef boost::container::vector int_vector_vector; +typedef allocator char_allocator; +typedef boost::container::basic_string, 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, 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 + 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 map_value_type; +typedef std::pair movable_to_map_value_type; +typedef allocator 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("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; +} +//] diff --git a/include/boost/interprocess/allocators/adaptive_pool.hpp b/include/boost/interprocess/allocators/adaptive_pool.hpp index e0c2fdc..25b1e58 100644 --- a/include/boost/interprocess/allocators/adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/adaptive_pool.hpp @@ -105,6 +105,7 @@ class adaptive_pool_base ::type const_reference; typedef typename segment_manager::size_type size_type; typedef typename segment_manager::difference_type difference_type; + typedef uses_segment_manager uses_segment_manager_t; typedef boost::interprocess::version_type version; typedef boost::container::dtl::transform_multiallocation_chain @@ -125,6 +126,8 @@ class adaptive_pool_base adaptive_pool_base& operator= (const adaptive_pool_base&); + 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) - //! Requires: Uses-allocator construction of T with allocator - //! `segment_manager*` and constructor arguments `std::forward(args)...` + //! Requires: Uses-allocator construction of T with allocator argument + //! `uses_segment_manager_t` and additional constructor arguments `std::forward(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 atd; boost::container::dtl::dispatch_uses_allocator - (atd, this->get_segment_manager(), p, ::boost::forward(args)...); + (atd, uses_segment_manager_t(this->get_segment_manager()), p, ::boost::forward(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 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 uses_segment_manager_t; + template 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 adaptive_pool_v1 (const adaptive_pool_v1 &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 version; + typedef boost::interprocess::version_type version; + typedef uses_segment_manager uses_segment_manager_t; template 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 adaptive_pool (const adaptive_pool &other) @@ -419,8 +433,8 @@ class adaptive_pool //!Never throws const_pointer address(const_reference value) const; - //! Requires: Uses-allocator construction of T with allocator - //! `segment_manager*` and constructor arguments `std::forward(args)...` + //! Requires: Uses-allocator construction of T with allocator argument + //! `uses_segment_manager_t` and additional constructor arguments `std::forward(args)...` //! is well-formed. [Note: uses-allocator construction is always well formed for //! types that do not use allocators. - end note] //! diff --git a/include/boost/interprocess/allocators/allocator.hpp b/include/boost/interprocess/allocators/allocator.hpp index d7efcc1..34ef74d 100644 --- a/include/boost/interprocess/allocators/allocator.hpp +++ b/include/boost/interprocess/allocators/allocator.hpp @@ -105,6 +105,7 @@ class allocator ::type const_reference; typedef typename segment_manager::size_type size_type; typedef typename segment_manager::difference_type difference_type; + typedef uses_segment_manager uses_segment_manager_t; typedef boost::interprocess::version_type version; @@ -113,6 +114,7 @@ class allocator //Experimental. Don't use. typedef boost::container::dtl::transform_multiallocation_chain 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) - //! Requires: Uses-allocator construction of T with allocator - //! `segment_manager*` and constructor arguments `std::forward(args)...` + //! Requires: Uses-allocator construction of T with allocator argument + //! `uses_segment_manager` and constructor arguments `std::forward(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 atd; boost::container::dtl::dispatch_uses_allocator - (atd, this->get_segment_manager(), p, ::boost::forward(args)...); + (atd, uses_segment_manager_t(this->get_segment_manager()), p, ::boost::forward(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 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) diff --git a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp index 8579911..b914a74 100644 --- a/include/boost/interprocess/allocators/cached_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/cached_adaptive_pool.hpp @@ -72,6 +72,8 @@ class cached_adaptive_pool_v1 > , 1> base_t; + typedef uses_segment_manager uses_segment_manager_t; + template 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 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 version; + typedef uses_segment_manager uses_segment_manager_t; template 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 cached_adaptive_pool (const cached_adaptive_pool &other) @@ -281,8 +294,8 @@ class cached_adaptive_pool //!Never throws const_pointer address(const_reference value) const; - //! Requires: Uses-allocator construction of T with allocator - //! `segment_manager*` and constructor arguments `std::forward(args)...` + //! Requires: Uses-allocator construction of T with allocator argument + //! `uses_segment_manager_t` and additional constructor arguments `std::forward(args)...` //! is well-formed. [Note: uses-allocator construction is always well formed for //! types that do not use allocators. - end note] //! diff --git a/include/boost/interprocess/allocators/cached_node_allocator.hpp b/include/boost/interprocess/allocators/cached_node_allocator.hpp index f00902d..669943b 100644 --- a/include/boost/interprocess/allocators/cached_node_allocator.hpp +++ b/include/boost/interprocess/allocators/cached_node_allocator.hpp @@ -69,6 +69,7 @@ class cached_node_allocator_v1 , NodesPerBlock > , 1> base_t; + typedef uses_segment_manager uses_segment_manager_t; template 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 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 version; - typedef typename base_t::size_type size_type; + typedef boost::interprocess::version_type version; + typedef typename base_t::size_type size_type; + typedef uses_segment_manager uses_segment_manager_t; template 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 cached_node_allocator (const cached_node_allocator &other) @@ -253,8 +265,8 @@ class cached_node_allocator //!Never throws pointer address(reference value) const; - //! Requires: Uses-allocator construction of T with allocator - //! `segment_manager*` and constructor arguments `std::forward(args)...` + //! Requires: Uses-allocator construction of T with allocator argument + //! `uses_segment_manager_t` and additional constructor arguments `std::forward(args)...` //! is well-formed. [Note: uses-allocator construction is always well formed for //! types that do not use allocators. - end note] //! diff --git a/include/boost/interprocess/allocators/detail/allocator_common.hpp b/include/boost/interprocess/allocators/detail/allocator_common.hpp index 0d166a3..6d8624f 100644 --- a/include/boost/interprocess/allocators/detail/allocator_common.hpp +++ b/include/boost/interprocess/allocators/detail/allocator_common.hpp @@ -78,6 +78,21 @@ struct sizeof_value static const std::size_t value = sizeof(void*); }; +template +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 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) - //! Requires: Uses-allocator construction of T with allocator - //! `segment_manager*` and constructor arguments `std::forward(args)...` + //! Requires: Uses-allocator construction of T with allocator argument + //! `uses_segment_manager_t` and additional constructor arguments `std::forward(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 atd; boost::container::dtl::dispatch_uses_allocator - (atd, this->get_segment_manager(), p, ::boost::forward(args)...); + (atd, uses_segment_manager_t(this->get_segment_manager()), p, ::boost::forward(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 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) diff --git a/include/boost/interprocess/allocators/node_allocator.hpp b/include/boost/interprocess/allocators/node_allocator.hpp index e07bc2e..2b0e695 100644 --- a/include/boost/interprocess/allocators/node_allocator.hpp +++ b/include/boost/interprocess/allocators/node_allocator.hpp @@ -106,6 +106,7 @@ class node_allocator_base typedef boost::interprocess::version_type version; typedef boost::container::dtl::transform_multiallocation_chain multiallocation_chain; + typedef uses_segment_manager 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) - //! Requires: Uses-allocator construction of T with allocator - //! `segment_manager*` and constructor arguments `std::forward(args)...` + //! Requires: Uses-allocator construction of T with allocator argument + //! `uses_segment_manager_t` and additional constructor arguments `std::forward(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 atd; boost::container::dtl::dispatch_uses_allocator - (atd, this->get_segment_manager(), p, ::boost::forward(args)...); + (atd, uses_segment_manager_t(this->get_segment_manager()), p, ::boost::forward(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 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 node_allocator_v1 (const node_allocator_v1 &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 node_allocator (const node_allocator &other) @@ -404,8 +413,8 @@ class node_allocator //!Never throws const_pointer address(const_reference value) const; - //! Requires: Uses-allocator construction of T with allocator - //! `segment_manager*` and constructor arguments `std::forward(args)...` + //! Requires: Uses-allocator construction of T with allocator argument + //! `uses_segment_manager_t` and additional constructor arguments `std::forward(args)...` //! is well-formed. [Note: uses-allocator construction is always well formed for //! types that do not use allocators. - end note] //! diff --git a/include/boost/interprocess/allocators/private_adaptive_pool.hpp b/include/boost/interprocess/allocators/private_adaptive_pool.hpp index cc1ac97..205aa70 100644 --- a/include/boost/interprocess/allocators/private_adaptive_pool.hpp +++ b/include/boost/interprocess/allocators/private_adaptive_pool.hpp @@ -104,6 +104,7 @@ class private_adaptive_pool_base version; typedef boost::container::dtl::transform_multiallocation_chain multiallocation_chain; + typedef uses_segment_manager uses_segment_manager_t; //!Obtains node_allocator from other node_allocator template @@ -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) - //! Requires: Uses-allocator construction of T with allocator - //! `segment_manager*` and constructor arguments `std::forward(args)...` + //! Requires: Uses-allocator construction of T with allocator argument + //! `uses_segment_manager_t` and additional constructor arguments `std::forward(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 atd; boost::container::dtl::dispatch_uses_allocator - (atd, this->get_segment_manager(), p, ::boost::forward(args)...); + (atd, uses_segment_manager_t(this->get_segment_manager()), p, ::boost::forward(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 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 uses_segment_manager_t; template 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 private_adaptive_pool_v1 (const private_adaptive_pool_v1 &other) @@ -327,7 +333,8 @@ class private_adaptive_pool BOOST_COPYABLE_AND_MOVABLE_ALT(private_adaptive_pool) public: - typedef boost::interprocess::version_type version; + typedef boost::interprocess::version_type version; + typedef uses_segment_manager uses_segment_manager_t; template 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 private_adaptive_pool (const private_adaptive_pool &other) @@ -449,8 +460,8 @@ class private_adaptive_pool //!Never throws const_pointer address(const_reference value) const; - //! Requires: Uses-allocator construction of T with allocator - //! `segment_manager*` and constructor arguments `std::forward(args)...` + //! Requires: Uses-allocator construction of T with allocator argument + //! `uses_segment_manager_t` and additional constructor arguments `std::forward(args)...` //! is well-formed. [Note: uses-allocator construction is always well formed for //! types that do not use allocators. - end note] //! diff --git a/include/boost/interprocess/allocators/private_node_allocator.hpp b/include/boost/interprocess/allocators/private_node_allocator.hpp index af42e48..19883d5 100644 --- a/include/boost/interprocess/allocators/private_node_allocator.hpp +++ b/include/boost/interprocess/allocators/private_node_allocator.hpp @@ -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 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) - //! Requires: Uses-allocator construction of T with allocator - //! `segment_manager*` and constructor arguments `std::forward(args)...` + //! Requires: Uses-allocator construction of T with allocator argument + //! `uses_segment_manager_t` and additional constructor arguments `std::forward(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 atd; boost::container::dtl::dispatch_uses_allocator - (atd, this->get_segment_manager(), p, ::boost::forward(args)...); + (atd, uses_segment_manager_t(this->get_segment_manager()), p, ::boost::forward(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 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 uses_segment_manager_t; template 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 private_node_allocator_v1 (const private_node_allocator_v1 &other) @@ -302,7 +308,9 @@ class private_node_allocator BOOST_COPYABLE_AND_MOVABLE_ALT(private_node_allocator) public: - typedef boost::interprocess::version_type version; + typedef boost::interprocess::version_type version; + typedef uses_segment_manager uses_segment_manager_t; + template 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 private_node_allocator (const private_node_allocator &other) @@ -424,8 +436,8 @@ class private_node_allocator //!Never throws const_pointer address(const_reference value) const; - //! Requires: Uses-allocator construction of T with allocator - //! `segment_manager*` and constructor arguments `std::forward(args)...` + //! Requires: Uses-allocator construction of T with allocator argument + //! `uses_segment_manager_t` and additional constructor arguments `std::forward(args)...` //! is well-formed. [Note: uses-allocator construction is always well formed for //! types that do not use allocators. - end note] //! diff --git a/include/boost/interprocess/detail/named_proxy.hpp b/include/boost/interprocess/detail/named_proxy.hpp index 4e18f34..910d19c 100644 --- a/include/boost/interprocess/detail/named_proxy.hpp +++ b/include/boost/interprocess/detail/named_proxy.hpp @@ -32,6 +32,8 @@ #include #endif //#ifdef BOOST_INTERPROCESS_PERFECT_FORWARDING #include +#include +#include #include @@ -73,13 +75,14 @@ struct CtorArgN : args_(args...) {} - void construct_n(void *mem, std::size_t num) + template + void construct_n(void *mem, SegmentManager *segment_manager, std::size_t num) { std::size_t constructed = 0; BOOST_INTERPROCESS_TRY{ T* memory = static_cast(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 - void construct(void *mem, true_, const index_tuple&) - { ::new((void*)mem, boost_container_new_t()) T(*boost::forward((get)(args_))...); } + template + void construct(void* mem, SegmentManager *segment_manager, true_, const index_tuple&) + { + boost::container::dtl::allocator_traits_dummy atd; + typedef uses_segment_manager uses_segment_manager_t; + boost::container::dtl::dispatch_uses_allocator + (atd, uses_segment_manager_t(segment_manager), static_cast(mem), *boost::forward((get)(args_))...); + } - template - void construct(void *mem, false_, const index_tuple&) - { ::new((void*)mem, boost_container_new_t()) T(boost::forward((get)(args_))...); } + //{ ::new((void*)mem, boost_container_new_t()) T(*boost::forward((get)(args_))...); } + template + void construct(void *mem, SegmentManager *segment_manager, false_, const index_tuple&) + { + typedef uses_segment_manager uses_segment_manager_t; + boost::container::dtl::allocator_traits_dummy atd; + boost::container::dtl::dispatch_uses_allocator + (atd, uses_segment_manager_t(segment_manager), static_cast(mem), boost::forward((get)(args_))...); + } + template void do_increment(true_, const index_tuple&) { @@ -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\ + void construct_n(void *mem, SegmentManager *segment_manager, std::size_t num)\ {\ std::size_t constructed = 0;\ BOOST_INTERPROCESS_TRY{\ T* memory = static_cast(mem);\ for (constructed = 0; constructed < num; ++constructed) {\ - ::new((void*)memory++) T ( BOOST_MOVE_MFWD##N );\ + boost::container::dtl::allocator_traits_dummy atd;\ + typedef uses_segment_manager 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\ + void construct_n(void *mem, SegmentManager *segment_manager, std::size_t num)\ {\ std::size_t constructed = 0;\ BOOST_INTERPROCESS_TRY{\ T* memory = static_cast(mem);\ for(constructed = 0; constructed < num; ++constructed){\ - ::new((void*)memory++) T( BOOST_MOVE_MITFWD##N );\ + boost::container::dtl::allocator_traits_dummy atd;\ + typedef uses_segment_manager 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);\ }\ }\ diff --git a/include/boost/interprocess/segment_manager.hpp b/include/boost/interprocess/segment_manager.hpp index 192dfef..1797848 100644 --- a/include/boost/interprocess/segment_manager.hpp +++ b/include/boost/interprocess/segment_manager.hpp @@ -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 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();