Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/memory/scoped allocator adaptor"

From cppreference.com
< cpp‎ | memory
(dcl list items templated)
(Added the entries of the exposition-only member function templates.)
 
(32 intermediate revisions by 11 users not shown)
Line 1: Line 1:
 
{{cpp/title|scoped_allocator_adaptor}}
 
{{cpp/title|scoped_allocator_adaptor}}
{{cpp/memory/scoped_allocator_adaptor/sidebar}}
+
{{cpp/memory/scoped_allocator_adaptor/navbar}}
{{ddcl list begin}}
+
{{ddcl|header=scoped_allocator|since=c++11|1=
{{ddcl list header| scoped_allocator}}
+
template< class OuterAlloc, class... InnerAllocs >
{{ddcl list item | notes={{mark since c++11}} |1=
+
class scoped_allocator_adaptor
template< class OuterAlloc, class... InnerAlloc >
+
    : public OuterAlloc;
class scoped_allocator_adaptor : public OuterAlloc;
+
 
}}
 
}}
{{ddcl list end}}
 
  
 
The {{tt|std::scoped_allocator_adaptor}} class template is an allocator which can be used with multilevel containers (vector of sets of lists of tuples of maps, etc). It is instantiated with one outer allocator type {{tt|OuterAlloc}} and zero or more inner allocator types {{tt|InnerAlloc...}}. A container constructed directly with a {{tt|scoped_allocator_adaptor}} uses {{tt|OuterAlloc}} to allocate its elements, but if an element is itself a container, it uses the first inner allocator. The elements of that container, if they are themselves containers, use the second inner allocator, etc. If there are more levels to the container than there are inner allocators, the last inner allocator is reused for all further nested containers.
 
The {{tt|std::scoped_allocator_adaptor}} class template is an allocator which can be used with multilevel containers (vector of sets of lists of tuples of maps, etc). It is instantiated with one outer allocator type {{tt|OuterAlloc}} and zero or more inner allocator types {{tt|InnerAlloc...}}. A container constructed directly with a {{tt|scoped_allocator_adaptor}} uses {{tt|OuterAlloc}} to allocate its elements, but if an element is itself a container, it uses the first inner allocator. The elements of that container, if they are themselves containers, use the second inner allocator, etc. If there are more levels to the container than there are inner allocators, the last inner allocator is reused for all further nested containers.
  
For the purpose of {{tt|scoped_allocator_adaptor}}, if the next inner allocator is {{tt|A}}, any class {{tt|T}} for which {{cpp|1=std::uses_allocator<T,A>::value == true}} participates in the recursion as if it was a container. Additionally, {{cpp|std::pair}} is treated as such a container by specific overloads of {{l2tt|cpp/memory/scoped_allocator_adaptor/construct}}.
+
The purpose of this adaptor is to correctly initialize stateful allocators in nested containers, such as when all levels of a nested container must be placed in the same shared memory segment. The adaptor's constructor takes the arguments for all allocators in the list, and each nested container obtains its allocator's state from the adaptor as needed.
  
===Member types===
+
For the purpose of {{tt|scoped_allocator_adaptor}}, if the next inner allocator is {{tt|A}}, any class {{tt|T}} for which {{c|1=std::uses_allocator<T,A>::value == true}} participates in the recursion as if it was a container. Additionally, {{lc|std::pair}} is treated as such a container by specific overloads of {{l2tt|cpp/memory/scoped_allocator_adaptor/construct}}.
{{tdcl list begin}}
+
{{tdcl list hitem | Type | Definition }}
+
{{tdcl list item | {{tt|outer_allocator_type}} | {{cpp|OuterAlloc}} }}
+
{{tdcl list item | {{tt|inner_allocator_type}} | {{cpp|scoped_allocator_adaptor<InnerAllocs...>}} or, if {{cpp|1=sizeof...(InnerAllocs) == 0}}, {{cpp|scoped_allocator_adaptor<OuterAlloc>}}}}
+
{{tdcl list item | {{tt|value_type}} | {{cpp|std::allocator_traits<OuterAlloc>::value_type}} }}
+
{{tdcl list item | {{tt|size_type}} | {{cpp|std::allocator_traits<OuterAlloc>::size_type}} }}
+
{{tdcl list item | {{tt|difference_type}} | {{cpp|std::allocator_traits<OuterAlloc>::difference_type}} }}
+
{{tdcl list item | {{tt|pointer}} | {{cpp|std::allocator_traits<OuterAlloc>::pointer}} }}
+
{{tdcl list item | {{tt|const_pointer}} | {{cpp|std::allocator_traits<OuterAlloc>::const_pointer}} }}
+
{{tdcl list item | {{tt|void_pointer}} | {{cpp|std::allocator_traits<OuterAlloc>::void_pointer}} }}
+
{{tdcl list item | {{tt|const_void_pointer}} | {{cpp|std::allocator_traits<OuterAlloc>::const_void_pointer}} }}
+
{{tdcl list item | {{tt|propagate_on_container_copy_assignment}}
+
::{{cpp|std::true_type}} if {{cpp|std::allocator_traits<A>::propagate_on_container_copy_assignment::value}} is {{cpp|true}} for at least one allocator {{tt|A}} among {{tt|OuterAlloc}} and {{tt|InnerAlloc...}} }}
+
{{tdcl list item | {{tt|propagate_on_container_move_assignment}}
+
::{{cpp|std::true_type}} if {{cpp|std::allocator_traits<A>::propagate_on_container_move_assignment::value}} is {{cpp|true}} for at least one allocator {{tt|A}} among {{tt|OuterAlloc}} and {{tt|InnerAlloc...}} }}
+
{{tdcl list item | {{tt|propagate_on_container_swap}}
+
::{{cpp|std::true_type}} if {{cpp|std::allocator_traits<A>::propagate_on_container_swap::value}} is {{cpp|true}} for at least one allocator {{tt|A}} among {{tt|OuterAlloc}} and {{tt|InnerAlloc...}} }}
+
{{tdcl list item | {{tt|rebind}}
+
  
<div style{{=}}"padding-left:3em; max-width: 50em; overflow: hidden;">
+
Typical implementation holds an instance of a {{tt|std::scoped_allocator_adaptor<InnerAllocs...>}} as a member object.
{{source cpp|template< class T >
+
 
struct rebind {
+
Note that {{ltt|cpp/memory/polymorphic_allocator|std::pmr::polymorphic_allocator}}s propagate to nested containers following {{lsd|cpp/memory/uses allocator#Uses-allocator construction}} and do not need (and do not work with) {{tt|std::scoped_allocator_adaptor}}.
    typedef scoped_allocator_adaptor<
+
 
        std::allocator_traits<OuterAlloc>::template rebind_alloc<T>,
+
===Nested types===
        InnerAllocs...
+
{{dsc begin}}
    > other;
+
{{dsc hitem|Type|Definition}}
};
+
{{dsc|{{tt|outer_allocator_type}}|{{tt|OuterAlloc}}}}
}}  
+
{{dsc|{{tt|inner_allocator_type}}|
</div>}}
+
* {{c/core|scoped_allocator_adaptor<InnerAllocs...>}} if {{c|1=sizeof...(InnerAllocs)}} is zero
{{tdcl list end}}
+
* {{c/core|scoped_allocator_adaptor<OuterAlloc>}} otherwise}}
 +
{{dsc|{{tt|value_type}}|{{c/core|std::allocator_traits<OuterAlloc>::value_type}}}}
 +
{{dsc|{{tt|size_type}}|{{c/core|std::allocator_traits<OuterAlloc>::size_type}}}}
 +
{{dsc|{{tt|difference_type}}|{{c/core|std::allocator_traits<OuterAlloc>::difference_type}}}}
 +
{{dsc|{{tt|pointer}}|{{c/core|std::allocator_traits<OuterAlloc>::pointer}}}}
 +
{{dsc|{{tt|const_pointer}}|{{c/core|std::allocator_traits<OuterAlloc>::const_pointer}}}}
 +
{{dsc|{{tt|void_pointer}}|{{c/core|std::allocator_traits<OuterAlloc>::void_pointer}}}}
 +
{{dsc|{{tt|const_void_pointer}}|{{c/core|std::allocator_traits<OuterAlloc>::const_void_pointer}}}}
 +
{{dsc end}}
 +
 
 +
 
 +
Given the set of {{tt|OuterAlloc}} and {{tt|InnerAlloc...}} as {{tt|Allocs}}:
 +
{{dsc begin}}
 +
{{dsc hitem|Type|Definition}}
 +
{{dsc|{{tt|propagate_on_container_copy_assignment}}|
 +
* {{lc|std::true_type}} if there exists a type {{tt|A}} in {{tt|Allocs}} such that {{c multi|std::allocator_traits<A>::|    propagate_on_container_copy_assignment::value}} is {{c|true}}
 +
* {{lc|std::false_type}} otherwise}}
 +
{{dsc|{{tt|propagate_on_container_move_assignment}}|
 +
* {{lc|std::true_type}} if there exists a type {{tt|A}} in {{tt|Allocs}} such that {{c multi|std::allocator_traits<A>::|    propagate_on_container_move_assignment::value}} is {{c|true}}
 +
* {{lc|std::false_type}} otherwise}}
 +
{{dsc|{{tt|propagate_on_container_swap}}|
 +
* {{lc|std::true_type}} if there exists a type {{tt|A}} in {{tt|Allocs}} such that {{c multi|std::allocator_traits<A>::|    propagate_on_container_swap::value}} is {{c|true}}
 +
* {{lc|std::false_type}} otherwise}}
 +
{{dsc|{{tt|is_always_equal}}|
 +
* {{lc|std::true_type}} if there exists a type {{tt|A}} in {{tt|Allocs}} such that {{c multi|std::allocator_traits<A>::|    is_always_equal::value}} is {{c|true}}
 +
* {{lc|std::false_type}} otherwise}}
 +
{{dsc end}}
  
 
===Member functions===
 
===Member functions===
{{dcl list begin}}
+
{{dsc begin}}
{{dcl list template | cpp/memory/scoped_allocator_adaptor/dcl list scoped_allocator_adaptor}}
+
{{dsc inc|cpp/memory/scoped_allocator_adaptor/dsc scoped_allocator_adaptor}}
{{dcl list template | cpp/memory/scoped_allocator_adaptor/dcl list ~scoped_allocator_adaptor}}
+
{{dsc inc|cpp/memory/scoped_allocator_adaptor/dsc ~scoped_allocator_adaptor}}
{{dcl list template | cpp/memory/scoped_allocator_adaptor/dcl list inner_allocator}}
+
{{dsc inc|cpp/memory/scoped_allocator_adaptor/dsc operator{{=}}}}
{{dcl list template | cpp/memory/scoped_allocator_adaptor/dcl list outer_allocator}}
+
{{dsc inc|cpp/memory/scoped_allocator_adaptor/dsc inner_allocator}}
{{dcl list template | cpp/memory/scoped_allocator_adaptor/dcl list allocate}}
+
{{dsc inc|cpp/memory/scoped_allocator_adaptor/dsc outer_allocator}}
{{dcl list template | cpp/memory/scoped_allocator_adaptor/dcl list deallocate}}
+
{{dsc inc|cpp/memory/scoped_allocator_adaptor/dsc allocate}}
{{dcl list template | cpp/memory/scoped_allocator_adaptor/dcl list max_size}}
+
{{dsc inc|cpp/memory/scoped_allocator_adaptor/dsc deallocate}}
{{dcl list template | cpp/memory/scoped_allocator_adaptor/dcl list construct}}
+
{{dsc inc|cpp/memory/scoped_allocator_adaptor/dsc max_size}}
{{dcl list template | cpp/memory/scoped_allocator_adaptor/dcl list destroy}}
+
{{dsc inc|cpp/memory/scoped_allocator_adaptor/dsc construct}}
{{dcl list template | cpp/memory/scoped_allocator_adaptor/dcl list select_on_container_copy_construction}}
+
{{dsc inc|cpp/memory/scoped_allocator_adaptor/dsc destroy}}
{{dcl list end}}
+
{{dsc inc|cpp/memory/scoped_allocator_adaptor/dsc select_on_container_copy_construction}}
 +
{{dsc h2|Exposition-only function templates}}
 +
{{dsc expos mem fun|cpp/memory/scoped_allocator_adaptor/helpers|title=''outermost''|obtains the outermost allocator}}
 +
{{dsc expos mem fun|cpp/memory/scoped_allocator_adaptor/helpers|title=''outermost-construct''|constructs an object using the outermost allocator}}
 +
{{dsc expos mem fun|cpp/memory/scoped_allocator_adaptor/helpers|title=''outermost-destroy''|destroys an object using the outermost allocator}}
 +
{{dsc end}}
  
 
===Non-member functions===
 
===Non-member functions===
{{dcl list begin}}
+
{{dsc begin}}
{{dcl list template | cpp/memory/scoped_allocator_adaptor/dcl list operator_cmp}}
+
{{dsc inc|cpp/memory/scoped_allocator_adaptor/dsc operator cmp}}
{{dcl list end}}
+
{{dsc end}}
 +
 
 +
===[[cpp/memory/scoped_allocator_adaptor/deduction guides|Deduction guides]]{{mark since c++17}}===
 +
 
 +
===Nested classes===
 +
{{dsc begin}}
 +
{{dsc hitem|Class|Definition}}
 +
{{dsc|{{tt|rebind}}{{nbsp}}|{{c|
 +
template< class T >
 +
struct rebind
 +
{
 +
    using other {{=}} scoped_allocator_adaptor
 +
                      <std::allocator_traits<OuterAlloc>::template rebind_alloc<T>,
 +
                      InnerAllocs...>;
 +
};
 +
}}
 +
}}
 +
{{dsc end}}
 +
 
 +
===Example===
 +
{{example
 +
|code=
 +
#include <boost/interprocess/allocators/adaptive_pool.hpp>
 +
#include <boost/interprocess/managed_shared_memory.hpp>
 +
#include <scoped_allocator>
 +
#include <vector>
 +
 
 +
namespace bi = boost::interprocess;
 +
 
 +
template<class T>
 +
using alloc = bi::adaptive_pool<T, bi::managed_shared_memory::segment_manager>;
 +
 
 +
using ipc_row = std::vector<int, alloc<int>>;
 +
 
 +
using ipc_matrix = std::vector<ipc_row, std::scoped_allocator_adaptor<alloc<ipc_row>>>;
 +
 
 +
int main()
 +
{
 +
    bi::managed_shared_memory s(bi::create_only, "Demo", 65536);
 +
   
 +
    // create vector of vectors in shared memory
 +
    ipc_matrix v(s.get_segment_manager());
 +
   
 +
    // for all these additions, the inner vectors obtain their allocator arguments
 +
    // from the outer vector's scoped_allocator_adaptor
 +
    v.resize(1);
 +
    v[0].push_back(1);
 +
    v.emplace_back(2);
 +
    std::vector<int> local_row = {1, 2, 3};
 +
    v.emplace_back(local_row.begin(), local_row.end());
 +
   
 +
    bi::shared_memory_object::remove("Demo");
 +
}
 +
}}
 +
 
 +
===Defect reports===
 +
{{dr list begin}}
 +
{{dr list item|wg=lwg|std=C++11|dr=2108|before=there was no way to show if {{tt|scoped_allocator_adaptor}} is stateless|after=provided {{tt|is_always_equal}}}}
 +
{{dr list end}}
  
 
===See also===
 
===See also===
{{dcl list begin}}
+
{{dsc begin}}
{{dcl list template | cpp/memory/dcl list allocator_traits}}
+
{{dsc inc|cpp/memory/dsc allocator_traits}}
{{dcl list template | cpp/memory/dcl list uses_allocator}}
+
{{dsc inc|cpp/memory/dsc uses_allocator}}
{{dcl list template | cpp/memory/dcl list allocator}}
+
{{dsc inc|cpp/memory/dsc allocator}}
{{dcl list end}}
+
{{dsc end}}
 +
 
 +
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}

Latest revision as of 01:59, 13 November 2024

 
 
Dynamic memory management
Uninitialized memory algorithms
Constrained uninitialized memory algorithms
Allocators
Garbage collection support
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)



 
 
Defined in header <scoped_allocator>
template< class OuterAlloc, class... InnerAllocs >

class scoped_allocator_adaptor

    : public OuterAlloc;
(since C++11)

The std::scoped_allocator_adaptor class template is an allocator which can be used with multilevel containers (vector of sets of lists of tuples of maps, etc). It is instantiated with one outer allocator type OuterAlloc and zero or more inner allocator types InnerAlloc.... A container constructed directly with a scoped_allocator_adaptor uses OuterAlloc to allocate its elements, but if an element is itself a container, it uses the first inner allocator. The elements of that container, if they are themselves containers, use the second inner allocator, etc. If there are more levels to the container than there are inner allocators, the last inner allocator is reused for all further nested containers.

The purpose of this adaptor is to correctly initialize stateful allocators in nested containers, such as when all levels of a nested container must be placed in the same shared memory segment. The adaptor's constructor takes the arguments for all allocators in the list, and each nested container obtains its allocator's state from the adaptor as needed.

For the purpose of scoped_allocator_adaptor, if the next inner allocator is A, any class T for which std::uses_allocator<T,A>::value == true participates in the recursion as if it was a container. Additionally, std::pair is treated as such a container by specific overloads of scoped_allocator_adaptor::construct.

Typical implementation holds an instance of a std::scoped_allocator_adaptor<InnerAllocs...> as a member object.

Note that std::pmr::polymorphic_allocators propagate to nested containers following uses-allocator construction and do not need (and do not work with) std::scoped_allocator_adaptor.

Contents

[edit] Nested types

Type Definition
outer_allocator_type OuterAlloc
inner_allocator_type
  • scoped_allocator_adaptor<InnerAllocs...> if sizeof...(InnerAllocs) is zero
  • scoped_allocator_adaptor<OuterAlloc> otherwise
value_type std::allocator_traits<OuterAlloc>::value_type
size_type std::allocator_traits<OuterAlloc>::size_type
difference_type std::allocator_traits<OuterAlloc>::difference_type
pointer std::allocator_traits<OuterAlloc>::pointer
const_pointer std::allocator_traits<OuterAlloc>::const_pointer
void_pointer std::allocator_traits<OuterAlloc>::void_pointer
const_void_pointer std::allocator_traits<OuterAlloc>::const_void_pointer


Given the set of OuterAlloc and InnerAlloc... as Allocs:

Type Definition
propagate_on_container_copy_assignment
propagate_on_container_move_assignment
propagate_on_container_swap
is_always_equal

[edit] Member functions

creates a new scoped_allocator_adaptor object
(public member function) [edit]
destructs a scoped_allocator_adaptor object
(public member function) [edit]
assigns a scoped_allocator_adaptor
(public member function) [edit]
obtains an inner_allocator reference
(public member function) [edit]
obtains an outer_allocator reference
(public member function) [edit]
allocates uninitialized storage using the outer allocator
(public member function) [edit]
deallocates storage using the outer allocator
(public member function) [edit]
returns the largest allocation size supported by the outer allocator
(public member function) [edit]
constructs an object in allocated storage, passing the inner allocator to its constructor if appropriate
(public member function) [edit]
destructs an object in allocated storage
(public member function) [edit]
copies the state of scoped_allocator_adaptor and all its allocators
(public member function) [edit]
Exposition-only function templates
obtains the outermost allocator
(exposition-only member function*)
constructs an object using the outermost allocator
(exposition-only member function*)
destroys an object using the outermost allocator
(exposition-only member function*)

[edit] Non-member functions

(removed in C++20)
compares two scoped_allocator_adaptor objects
(function template) [edit]

[edit] Deduction guides(since C++17)

[edit] Nested classes

Class Definition
rebind  template< class T >

struct rebind
{
    using other = scoped_allocator_adaptor
                      <std::allocator_traits<OuterAlloc>::template rebind_alloc<T>,
                       InnerAllocs...>;
};

[edit] Example

#include <boost/interprocess/allocators/adaptive_pool.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <scoped_allocator>
#include <vector>
 
namespace bi = boost::interprocess;
 
template<class T>
using alloc = bi::adaptive_pool<T, bi::managed_shared_memory::segment_manager>;
 
using ipc_row = std::vector<int, alloc<int>>;
 
using ipc_matrix = std::vector<ipc_row, std::scoped_allocator_adaptor<alloc<ipc_row>>>;
 
int main()
{
    bi::managed_shared_memory s(bi::create_only, "Demo", 65536);
 
    // create vector of vectors in shared memory
    ipc_matrix v(s.get_segment_manager());
 
    // for all these additions, the inner vectors obtain their allocator arguments
    // from the outer vector's scoped_allocator_adaptor
    v.resize(1);
    v[0].push_back(1);
    v.emplace_back(2);
    std::vector<int> local_row = {1, 2, 3};
    v.emplace_back(local_row.begin(), local_row.end());
 
    bi::shared_memory_object::remove("Demo");
}

[edit] Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
LWG 2108 C++11 there was no way to show if scoped_allocator_adaptor is stateless provided is_always_equal

[edit] See also

provides information about allocator types
(class template) [edit]
checks if the specified type supports uses-allocator construction
(class template) [edit]
the default allocator
(class template) [edit]