Namespaces
Variants
Views
Actions

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

From cppreference.com
(P0475)
m (Typo fix.)
 
(8 intermediate revisions by 6 users not shown)
Line 2: Line 2:
 
{{cpp/memory/scoped_allocator_adaptor/navbar}}
 
{{cpp/memory/scoped_allocator_adaptor/navbar}}
 
{{dcl begin}}
 
{{dcl begin}}
{{dcl header | scoped_allocator}}
+
{{dcl header|scoped_allocator}}
{{dcl | num=1 |
+
{{dcl|num=1|
template < class T, class... Args >
+
template< class T, class... Args >
 
void construct( T* p, Args&&... args );
 
void construct( T* p, Args&&... args );
 
}}
 
}}
{{dcl | num=2 |
+
{{dcl|num=2|until=c++20|
 
template< class T1, class T2, class... Args1, class... Args2 >
 
template< class T1, class T2, class... Args1, class... Args2 >
void construct( std::pair<T1, T2>* p,
+
void construct( std::pair<T1, T2>* p, std::piecewise_construct_t,
                std::piecewise_construct_t,
+
                 std::tuple<Args1...> x, std::tuple<Args2...> y );
                 std::tuple<Args1...> x,
+
                std::tuple<Args2...> y );
+
 
}}
 
}}
{{dcl | num=3 |
+
{{dcl|num=3|until=c++20|
 
template< class T1, class T2 >
 
template< class T1, class T2 >
 
void construct( std::pair<T1, T2>* p );
 
void construct( std::pair<T1, T2>* p );
 
}}
 
}}
{{dcl | num=4|
+
{{dcl|num=4|until=c++20|
 
template< class T1, class T2, class U, class V >
 
template< class T1, class T2, class U, class V >
 
void construct( std::pair<T1, T2>* p, U&& x, V&& y );
 
void construct( std::pair<T1, T2>* p, U&& x, V&& y );
 
}}
 
}}
{{dcl | num=5|
+
{{dcl|num=5|until=c++20|
 
template< class T1, class T2, class U, class V >
 
template< class T1, class T2, class U, class V >
 
void construct( std::pair<T1, T2>* p, const std::pair<U, V>& xy );
 
void construct( std::pair<T1, T2>* p, const std::pair<U, V>& xy );
 
}}
 
}}
{{dcl | num=6|
+
{{dcl|num=6|until=c++20|
 
template< class T1, class T2, class U, class V >
 
template< class T1, class T2, class U, class V >
 
void construct( std::pair<T1, T2>* p, std::pair<U, V>&& xy );
 
void construct( std::pair<T1, T2>* p, std::pair<U, V>&& xy );
 +
}}
 +
{{dcl h|Helper function templates}}
 +
{{dcla|num=7|until=c++20|expos=yes|
 +
template < class T, class... Args >
 +
std::tuple</* see below */> /*concat-args*/( std::tuple<Args...>&& tup );
 
}}
 
}}
 
{{dcl end}}
 
{{dcl end}}
  
Constructs an object in allocated, but not initialized storage pointed to by {{tt|p}} using OuterAllocator and the provided constructor arguments. If the object is of type that itself uses allocators, or if it is std::pair, passes InnerAllocator down to the constructed object.
+
Constructs an object in allocated, but not initialized storage pointed to by {{c|p}} using the outer allocator and the provided constructor arguments. If the object is of a type that itself uses allocators{{rev inl|until=c++20|, or if it is {{lc|std::pair}}}}, passes the inner allocator down to the constructed object.
  
First, retrieve the outermost allocator {{tt|OUTERMOST}} by calling {{c|this->outer_allocator()}}, and then calling the {{tt|outer_allocator()}} member function recursively on the result of this call until reaching an allocator that has no such member function. Let {{tt|O}} be the type of {{tt|OUTERMOST}}.
+
@1@ Constructs an object of type {{tt|T}} by [[cpp/memory/uses_allocator#Uses-allocator_construction|uses-allocator construction]] at the uninitialized memory location indicated by {{c|p}} using the outermost allocator.
 +
{{rev begin}}
 +
{{rev|until=c++20|
 +
Given {{c|std::uses_allocator<T, inner_allocator_type>::value}} as {{c|uses_inner}}:
 +
* If {{c|uses_inner}} is {{c|false}} and {{c|std::is_constructible<T, Args...>::value}} is {{c|true}}, calls {{box|{{rlpsi|helpers#outermost-construct}}{{sep}}{{c/core|(p, std::forward<Args>(args)...)}}}}.
 +
* Otherwise, if {{c|uses_inner}} and {{c multi|std::is_constructible<T, std::allocator_arg_t,|                      inner_allocator_type&,|                      Args...>::value}} are both {{c|true}}, calls {{box|{{rlpsi|helpers#outermost-construct}}{{sep}}{{c/core|(p, std::allocator_arg,}}<br>{{nbspt|20}}{{c/core|inner_allocator(),}}<br>{{nbspt|20}}{{c/core|std::forward<Args>(args)...)}}}}.
 +
* Otherwise, if {{c|uses_inner}} and {{c|std::is_constructible<T, Args..., inner_allocator_type&>::value}} are both {{c|true}}, calls {{box|{{rlpsi|helpers#outermost-construct}}{{sep}}{{c/core|(p, std::forward<Args>(args)..., inner_allocator())}}}}.
 +
* Otherwise, the program is ill-formed.
  
Then:
+
{{cpp/enable if|{{tt|T}} is not a specialization of {{lc|std::pair}}}}.
 
+
1) If {{c|1=std::uses_allocator<T, inner_allocator_type>::value==false}} (the type {{tt|T}} does not use allocators) and if {{c|1=std::is_constructible<T, Args...>::value==true}}, then calls
+
 
+
{{c|
+
std::allocator_traits<O>::construct( OUTERMOST,
+
                                    p,
+
                                    std::forward<Args>(args)... );
+
 
}}
 
}}
 
+
{{rev|since=c++20|
Otherwise, if {{c|1=std::uses_allocator<T, inner_allocator_type>::value==true}} (the type {{tt|T}} uses allocators, e.g. it is a container) and if {{c|1=std::is_constructible<T, std::allocator_arg_t, inner_allocator_type&, Args...>::value==true}}, then calls
+
Equivalent to {{box|
 
+
{{c/core|std::apply}}<br>
{{c|
+
{{c/core|(}}<br>
std::allocator_traits<O>::construct( OUTERMOST,
+
{{nbspt|4}}{{c/core|[p, this](auto&&... newargs)}}<br>
                                    p,
+
{{nbspt|4}}{{c/core|{}}<br>
                                    std::allocator_arg,
+
{{nbspt|8}}{{rlpsi|helpers#outermost-construct}}<br>
                                    inner_allocator(),
+
{{nbspt|12}}{{c/core|(p, std::forward<decltype(newargs)>(newargs)...);}}<br>
                                    std::forward<Args>(args)... );
+
{{nbspt|4}}{{c/core|},}}<br>
 +
{{nbspt|4}}{{c/core|std::uses_allocator_construction_args}}<br>
 +
{{nbspt|8}}{{c/core|(inner_allocator(), std::forward<Args>(args)...)}}<br>
 +
{{c/core|);}}
 +
}}.
 
}}
 
}}
 +
{{rev end}}
  
Otherwise, {{c|1=std::uses_allocator<T, inner_allocator_type>::value==true}} (the type {{tt|T}} uses allocators, e.g. it is a container) and if {{c|1=std::is_constructible<T, Args..., inner_allocator_type&>::value==true}}, then calls
+
@2-6@ Constructs a {{lc|std::pair}} object by [[cpp/memory/uses_allocator#Uses-allocator_construction|uses-allocator construction]] at the uninitialized memory location indicated by {{c|p}} using the outermost allocator.
  
{{c|
+
:@2@ Let {{c|xprime}} be {{box|{{tti|concat-args}}{{sep}}{{c/core|<T1>(std::move(x))}}}}, {{c|yprime}} be {{box|{{tti|concat-args}}{{sep}}{{c/core|<T2>(std::move(y))}}}}, calls {{box|{{rlpsi|helpers#outermost-construct}}{{sep}}{{c/core|(p, std::piecewise_construct, std::move(xprime), std::move(yprime))}}}}.
std::allocator_traits<O>::construct( OUTERMOST,
+
                                    p,
+
                                    std::forward<Args>(args)...,
+
                                    inner_allocator());
+
}}
+
  
Otherwise, the program is ill-formed: even though {{tt|std::uses_allocator<T>}} claimed that {{tt|T}} is allocator-aware, it lacks either form of allocator-accepting constructors.
+
:@3@ Equivalent to {{c|construct(p, std::piecewise_construct, std::tuple<>(), std::tuple<>());}}.
  
{{cpp/enable if|{{tt|U}} is not a specialization of {{lc|std::pair}}}}.
+
:@4-6@ Equivalent to {{c multi|construct(p, std::piecewise_construct,|          std::forward_as_tuple(xarg), std::forward_as_tuple(yarg));}}, where {{c|xarg}} and {{c|yarg}} are defined as follows:
 +
{|class="wikitable" style="text-align: center;"
 +
!{{nbsp}}Overload{{nbsp}}
 +
!{{normal|{{c|xarg}}}}
 +
!{{normal|{{c|yarg}}}}
 +
|-
 +
|{{v|4}}
 +
|{{c|std::forward<U>(x)}}
 +
|{{c|std::forward<V>(y)}}
 +
|-
 +
|{{v|5}}
 +
|{{c|xy.first}}
 +
|{{c|xy.second}}
 +
|-
 +
|{{v|6}}
 +
|{{c|std::forward<U>(xy.first)}}
 +
|{{c|std::forward<V>(xy.second)}}
 +
|}
  
2) First, if either {{tt|T1}} or {{tt|T2}} is allocator-aware, modifies the tuples {{tt|x}} and {{tt|y}} to include the appropriate inner allocator, resulting in the two new tuples {{tt|xprime}} and {{tt|yprime}}, according to the following three rules:
+
@7@ Merges the arguments contained in {{c|tup}} and additional arguments required by [[cpp/memory/uses_allocator#Uses-allocator_construction|uses-allocator construction]] of an object of type {{tt|T}}.
 
+
@@ Given {{c|std::uses_allocator<T, inner_allocator_type>::value}} as {{c|uses_inner}}:
2a) if {{tt|T1}} is not allocator-aware ({{c|1=std::uses_allocator<T1, inner_allocator_type>::value==false}}, then {{tt|xprime}} is  {{c|std::tuple<Args1&&...>(std::move(x))}}. (it is also required that {{c|1=std::is_constructible<T1, Args1...>::value==true}})
+
* If {{c|uses_inner}} is {{c|false}} and {{c|std::is_constructible<T, Args...>::value}} is {{c|true}}, returns {{c|std::tuple<Args&&...>(std::move(tup))}}.
 
+
* Otherwise, if {{c|uses_inner}} and {{c multi|std::is_constructible<T, std::allocator_arg_t,|                      inner_allocator_type&,|                      Args...>::value}} are both {{c|true}}, returns {{c multi|std::tuple_cat(std::tuple<std::allocator_arg_t, inner_allocator_type&>|                  (std::allocator_arg, inner_allocator()),|              std::tuple<Args&&...>(std::move(tup)))}}.
2b) if {{tt|T1}} is allocator-aware ({{c|1=std::uses_allocator<T1, inner_allocator_type>::value==true}}), and its constructor takes an allocator tag ({{c|1=std::is_constructible<T1, std::allocator_arg_t, inner_allocator_type&, Args1...>::value==true}}), then {{tt|xprime}} is
+
* Otherwise, if {{c|uses_inner}} and {{c|std::is_constructible<T, Args..., inner_allocator_type&>::value}} are both {{c|true}}, returns {{c multi|std::tuple_cat(std::tuple<Args&&...>(std::move(tup)),|              std::tuple<inner_allocator_type&>(inner_allocator())}}.
{{c|std::tuple_cat( std::tuple<std::allocator_arg_t, inner_allocator_type&>( std::allocator_arg,
+
* Otherwise, the program is ill-formed.
                                                                        inner_allocator()
+
                                                                      ), std::tuple<Args1&&...>(std::move(x)))}}
+
 
+
2c) if {{tt|T1}} is allocator-aware ({{c|1=std::uses_allocator<T1, inner_allocator_type>::value==true}}), and its constructor takes the allocator as the last argument ({{c|1=std::is_constructible<T1, Args1..., inner_allocator_type&>::value==true}}), then {{tt|xprime}} is  {{c|std::tuple_cat(std::tuple<Args1&&...>(std::move(x)), std::tuple<inner_allocator_type&>(inner_allocator()))}}.
+
 
+
Same rules apply to {{tt|T2}} and the replacement of {{tt|y}} with {{tt|yprime}}
+
 
+
Once {{tt|xprime}} and {{tt|yprime}} are constructed, constructs the pair {{tt|p}} in allocated storage by calling
+
 
+
{{c|
+
std::allocator_traits<O>::construct( OUTERMOST,
+
                                    p,
+
                                    std::piecewise_construct,
+
                                    std::move(xprime),
+
                                    std::move(yprime));
+
}}
+
 
+
 
+
3) Equivalent to {{c|construct(p, std::piecewise_construct, std::tuple<>(), std::tuple<>())}}, that is, passes the inner allocator on to the pair's member types if they accept them.
+
 
+
4) Equivalent to
+
 
+
{{c|
+
    construct(p, std::piecewise_construct, std::forward_as_tuple(std::forward<U>(x)),
+
                                          std::forward_as_tuple(std::forward<V>(y)))
+
}}
+
 
+
5) Equivalent to
+
 
+
{{c|
+
    construct(p, std::piecewise_construct, std::forward_as_tuple(xy.first),
+
                                          std::forward_as_tuple(xy.second))
+
}}
+
 
+
6) Equivalent to
+
 
+
{{c|
+
    construct(p, std::piecewise_construct, std::forward_as_tuple(std::forward<U>(xy.first)),
+
                                          std::forward_as_tuple(std::forward<V>(xy.second)))
+
}}
+
  
 
===Parameters===
 
===Parameters===
 
{{par begin}}
 
{{par begin}}
{{par | p | pointer to allocated, but not initialized storage }}
+
{{par|p|pointer to allocated, but not initialized storage}}
{{par | args... | the constructor arguments to pass to the constructor of {{tt|T}} }}
+
{{par|args|the constructor arguments to pass to the constructor of {{tt|T}}}}
{{par | x | the constructor arguments to pass to the constructor of {{tt|T1}} }}
+
{{par|x|the constructor arguments to pass to the constructor of {{tt|T1}}}}
{{par | y | the constructor arguments to pass to the constructor of {{tt|T2}} }}
+
{{par|y|the constructor arguments to pass to the constructor of {{tt|T2}}}}
{{par | xy | the pair whose two members are the constructor arguments for {{tt|T1}} and {{tt|T2}} }}
+
{{par|xy|the pair whose two members are the constructor arguments for {{tt|T1}} and {{tt|T2}}}}
 +
{{par|tup|the arguments to be merged}}
 
{{par end}}
 
{{par end}}
 
===Return value===
 
(none)
 
  
 
===Notes===
 
===Notes===
This function is called (through {{lc|std::allocator_traits}}) by any allocator-aware object, such as {{lc|std::vector}}, that was given a {{lc|std::scoped_allocator_adaptor}} as the allocator to use. Since {{tt|inner_allocator}} is itself an instance of {{lc|std::scoped_allocator_adaptor}}, this function will also be called when the allocator-aware objects constructed through this function start constructing their own members.
+
This function is called (through {{lc|std::allocator_traits}}) by any allocator-aware object, such as {{lc|std::vector}}, that was given a {{lc|std::scoped_allocator_adaptor}} as the allocator to use. Since {{tt|inner_allocator_type}} is itself a specialization of {{lc|std::scoped_allocator_adaptor}}, this function will also be called when the allocator-aware objects constructed through this function start constructing their own members.
  
=== Defect reports ===
+
===Defect reports===
 
{{dr list begin}}
 
{{dr list begin}}
{{dr list item|wg=lwg|dr=2975|std=C++11|before=first overload is mistakenly used for pair construction in some cases|after=constrained to not accept pairs}}
+
{{dr list item|wg=lwg|dr=2203|std=C++11|before=inner allocators were obtained by value-initializing<br>an {{tt|inner_allocator_type}} object|after=obtained by calling {{rlpf|inner_allocator}}}}
{{dr list item|paper=P0475R1|std=C++11|before=pair piecewise construction may copy the arguments|after=transformed to tuples of references to avoid copy}}
+
{{dr list item|wg=lwg|dr=2511|paper=P0475R1|std=C++11|before={{tti|concat-args}} might copy elements of {{lc|std::tuple}}s|after=eliminated all element copy operations}}
 +
{{dr list item|wg=lwg|dr=2586|std=C++11|before=only constructions from<br>{{tt|inner_allocator_type}} rvalues were checked|after=checks constructions from non-const<br>{{tt|inner_allocator_type}} lvalues instead}}
 +
{{dr list item|wg=lwg|dr=2975|std=C++11|before=overload {{v|1}} was not constrained|after=constrained to refuse {{lc|std::pair}}}}
 
{{dr list end}}
 
{{dr list end}}
  
 
===See also===
 
===See also===
 
{{dsc begin}}
 
{{dsc begin}}
{{dsc inc | cpp/memory/allocator_traits/dsc construct}}
+
{{dsc inc|cpp/memory/allocator_traits/dsc construct}}
{{dsc inc | cpp/memory/allocator/dsc construct}}
+
{{dsc inc|cpp/memory/allocator/dsc construct}}
 
{{dsc end}}
 
{{dsc end}}
  
 
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}
 
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}

Latest revision as of 16:44, 14 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 T, class... Args >
void construct( T* p, Args&&... args );
(1)
template< class T1, class T2, class... Args1, class... Args2 >

void construct( std::pair<T1, T2>* p, std::piecewise_construct_t,

                std::tuple<Args1...> x, std::tuple<Args2...> y );
(2) (until C++20)
template< class T1, class T2 >
void construct( std::pair<T1, T2>* p );
(3) (until C++20)
template< class T1, class T2, class U, class V >
void construct( std::pair<T1, T2>* p, U&& x, V&& y );
(4) (until C++20)
template< class T1, class T2, class U, class V >
void construct( std::pair<T1, T2>* p, const std::pair<U, V>& xy );
(5) (until C++20)
template< class T1, class T2, class U, class V >
void construct( std::pair<T1, T2>* p, std::pair<U, V>&& xy );
(6) (until C++20)
Helper function templates
template < class T, class... Args >
std::tuple</* see below */> /*concat-args*/( std::tuple<Args...>&& tup );
(7) (exposition only*)
(until C++20)

Constructs an object in allocated, but not initialized storage pointed to by p using the outer allocator and the provided constructor arguments. If the object is of a type that itself uses allocators, or if it is std::pair(until C++20), passes the inner allocator down to the constructed object.

1) Constructs an object of type T by uses-allocator construction at the uninitialized memory location indicated by p using the outermost allocator.

Given std::uses_allocator<T, inner_allocator_type>::value as uses_inner:

This overload participates in overload resolution only if T is not a specialization of std::pair.

(until C++20)

Equivalent to std::apply
(
    [p, this](auto&&... newargs)
    {
        outermost-construct
            (p, std::forward<decltype(newargs)>(newargs)...);
    },
    std::uses_allocator_construction_args
        (inner_allocator(), std::forward<Args>(args)...)
);
.

(since C++20)
2-6) Constructs a std::pair object by uses-allocator construction at the uninitialized memory location indicated by p using the outermost allocator.
2) Let xprime be concat-args <T1>(std::move(x)), yprime be concat-args <T2>(std::move(y)), calls outermost-construct (p, std::piecewise_construct, std::move(xprime), std::move(yprime)).
3) Equivalent to construct(p, std::piecewise_construct, std::tuple<>(), std::tuple<>());.
4-6) Equivalent to construct(p, std::piecewise_construct,
          std::forward_as_tuple(xarg), std::forward_as_tuple(yarg));
, where xarg and yarg are defined as follows:
 Overload  xarg yarg
(4) std::forward<U>(x) std::forward<V>(y)
(5) xy.first xy.second
(6) std::forward<U>(xy.first) std::forward<V>(xy.second)
7) Merges the arguments contained in tup and additional arguments required by uses-allocator construction of an object of type T.
Given std::uses_allocator<T, inner_allocator_type>::value as uses_inner:

Contents

[edit] Parameters

p - pointer to allocated, but not initialized storage
args - the constructor arguments to pass to the constructor of T
x - the constructor arguments to pass to the constructor of T1
y - the constructor arguments to pass to the constructor of T2
xy - the pair whose two members are the constructor arguments for T1 and T2
tup - the arguments to be merged

[edit] Notes

This function is called (through std::allocator_traits) by any allocator-aware object, such as std::vector, that was given a std::scoped_allocator_adaptor as the allocator to use. Since inner_allocator_type is itself a specialization of std::scoped_allocator_adaptor, this function will also be called when the allocator-aware objects constructed through this function start constructing their own members.

[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 2203 C++11 inner allocators were obtained by value-initializing
an inner_allocator_type object
obtained by calling inner_allocator()
LWG 2511
(P0475R1)
C++11 concat-args might copy elements of std::tuples eliminated all element copy operations
LWG 2586 C++11 only constructions from
inner_allocator_type rvalues were checked
checks constructions from non-const
inner_allocator_type lvalues instead
LWG 2975 C++11 overload (1) was not constrained constrained to refuse std::pair

[edit] See also

[static]
constructs an object in the allocated storage
(function template) [edit]
(until C++20)
constructs an object in allocated storage
(public member function of std::allocator<T>) [edit]