Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/named req/AllocatorAwareContainer"

From cppreference.com
< cpp‎ | named req
m (+C++11 in title)
m (fmt)
Line 23: Line 23:
 
====Legend====
 
====Legend====
 
{{dsc begin}}
 
{{dsc begin}}
{{dsc|{{ttb|X}}|Container type}}
+
{{dsc|{{tt|X}}|Container type}}
{{dsc|{{ttb|T}}|Element type}}
+
{{dsc|{{tt|T}}|Element type}}
{{dsc|{{ttb|A}}|Allocator for {{ttb|T}} }}
+
{{dsc|{{tt|A}}|Allocator for {{tt|T}}}}
{{dsc|{{ttb|a}}, {{ttb|b}}|Objects of type {{ttb|X}} (non-const lvalue)}}
+
{{dsc|{{c|a}}, {{c|b}}|Objects of type {{tt|X}} (non-const lvalue)}}
{{dsc|{{ttb|t}}|Object of type {{ttb|X}} (lvalue or const rvalue) }}
+
{{dsc|{{c|t}}|Object of type {{tt|X}} (lvalue or const rvalue)}}
{{dsc|{{ttb|rv}}|Object of type {{ttb|X}} (non-const rvalue) }}
+
{{dsc|{{c|rv}}|Object of type {{tt|X}} (non-const rvalue)}}
{{dsc|{{ttb|m}}|Object of type {{ttb|A}} }}
+
{{dsc|{{c|m}}|Object of type {{tt|A}}}}
 
{{dsc end}}
 
{{dsc end}}
  
 +
====Types====
 
{|class=wikitable
 
{|class=wikitable
!expression||return type||pre/requirements||post/effects||complexity
+
!Expression||Return type||Requirements
 
|-
 
|-
|{{c|allocator_type}}||{{ttb|A}}||{{c|allocator_type::value_type}} must be the same as {{c|X::value_type}} || || compile-time
+
|{{tt|allocator_type}}||{{tt|A}}||{{c|allocator_type::value_type}} must be the same as {{c|X::value_type}}
 
|-
 
|-
|{{c|get_allocator()}}||{{ttb|A}}|| || || constant
+
|}
 +
 
 +
====Member functions and operators====
 +
{|class=wikitable
 +
!Expression||Return type||Pre/requirements||Post/effects||Complexity
 +
|-
 +
|{{c|get_allocator()}}||{{tt|A}}||||||Constant
 
|-
 
|-
|{{c|X u;}} || ||{{ttb|A}} is {{named req|DefaultConstructible}}|| {{c|u.empty() {{==}} true && u.get_allocator() {{==}} A()}} || constant
+
|{{c|X u;}}||||{{tt|A}} is {{named req|DefaultConstructible}}||{{c|u.empty() {{==}} true && u.get_allocator() {{==}} A()}}||Constant
 
|-
 
|-
|{{c|X u(m);}} || || || {{c|u.empty() {{==}} true && u.get_allocator() {{==}} m}} || constant
+
|{{c|X u(m);}}||||||{{c|u.empty() {{==}} true && u.get_allocator() {{==}} m}}||Constant
 
|-
 
|-
|{{c|X u(t,m);}} ||  
+
|{{c|X u(t,m);}}||
| {{ttb|T}} is {{named req|CopyInsertable}} into {{ttb|X}}
+
|{{tt|T}} is {{named req|CopyInsertable}} into {{tt|X}}
|{{c|u {{==}} t && u.get_allocator() {{==}} m}} || linear
+
|{{c|u {{==}} t && u.get_allocator() {{==}} m}}||Linear
 
|-
 
|-
|{{c|X u(rv);}} ||
+
|{{c|X u(rv);}}||
| Move constructor of {{ttb|A}} must not throw exceptions  
+
|Move constructor of {{tt|A}} must not throw exceptions
| {{ttb|u}} has the same elements and an equal allocator as {{ttb|rv}} had before the construction || constant
+
|{{c|u}} has the same elements and an equal allocator as {{c|rv}} had before the construction||Constant
 
|-
 
|-
|{{c|X u(rv,m);}}||  
+
|{{c|X u(rv,m);}}||
|{{ttb|T}} is {{named req|MoveInsertable}} into {{ttb|X}}
+
|{{tt|T}} is {{named req|MoveInsertable}} into {{tt|X}}
| The elements of {{ttb|u}} are the same or copies of those of {{ttb|rv}} and {{c|u.get_allocator() {{==}} m}}
+
|The elements of {{c|u}} are the same or copies of those of {{c|rv}} and {{c|u.get_allocator() {{==}} m}}
| constant if {{c|m {{==}} rv.get_allocator()}}, otherwise linear
+
|Constant if {{c|m {{==}} rv.get_allocator()}}, otherwise linear
 
|-
 
|-
 
|{{c|a {{=}} t}}||{{c|X&}}
 
|{{c|a {{=}} t}}||{{c|X&}}
|{{c|{{ttb|T}} is {{named req|CopyInsertable}} into {{ttb|X}} and {{named req|CopyAssignable}} ||{{c|a {{==}} t}} || linear
+
|{{tt|T}} is {{named req|CopyInsertable}} into {{tt|X}} and {{named req|CopyAssignable}}||{{c|a {{==}} t}}||Linear
 
|-
 
|-
 
|{{c|a {{=}} rv}}||{{c|X&}}
 
|{{c|a {{=}} rv}}||{{c|X&}}
|If the allocator will <i>not</i> be replaced by move-assignment (see above), then {{ttb|T}} is {{named req|MoveInsertable}} into {{ttb|X}} and {{named req|MoveAssignable}}
+
|If the allocator will ''not'' be replaced by move-assignment (see above), then {{tt|T}} is {{named req|MoveInsertable}} into {{tt|X}} and {{named req|MoveAssignable}}
|All existing elements of {{ttb|a}} are either move assigned to or destroyed; if {{ttb|a}} and {{ttb|rv}} do not refer the same object, {{ttb|a}} is equal to the value that {{ttb|rv}} had before the assignment|| linear
+
|All existing elements of {{c|a}} are either move assigned to or destroyed; if {{c|a}} and {{c|rv}} do not refer the same object, {{c|a}} is equal to the value that {{c|rv}} had before the assignment||Linear
 
|-
 
|-
|{{c|a.swap(b)}}||void|| || Exchanges the contents of {{ttb|a}} and {{ttb|b}} || constant
+
|{{c|a.swap(b)}}||{{c|void}}||||Exchanges the contents of {{c|a}} and {{c|b}}||Constant
 
|-
 
|-
 
|}
 
|}
  
 
===Notes===
 
===Notes===
Allocator-aware containers always call {{c|std::allocator_traits<A>::construct(m, p, args)}} to construct an object of type {{tt|T}} at {{tt|p}} using {{tt|args}}, with {{c|1=m == get_allocator()}}. {{rev inl|until=c++20|The default {{tt|construct}} in {{lc|std::allocator}} calls {{c|::new((void*)p) T(args)}}}}{{rev inl|since=c++20|{{lc|std::allocator}} has no {{tt|construct}} member and {{c|std::construct_at(p, args)}} is called when constructing elements}}, but specialized allocators may choose a different definition
+
Allocator-aware containers always call {{c|std::allocator_traits<A>::construct(m, p, args)}} to construct an object of type {{tt|T}} at {{c|p}} using {{c|args}}, with {{c|1=m == get_allocator()}}. {{rev inl|until=c++20|The default {{tt|construct}} in {{lc|std::allocator}} calls {{c|::new((void*)p) T(args)}}}}{{rev inl|since=c++20|{{lc|std::allocator}} has no {{tt|construct}} member and {{c|std::construct_at(p, args)}} is called when constructing elements}}, but specialized allocators may choose a different definition
  
 
===Standard library===
 
===Standard library===
Line 88: Line 95:
 
===Defect reports===
 
===Defect reports===
 
{{dr list begin}}
 
{{dr list begin}}
{{dr list item|wg=lwg|dr=2839|std=C++11|before=self move assignment of standard containers was not allowed|after=allowed but the result is unspecifed}}
+
{{dr list item|wg=lwg|dr=2839|std=C++11|before=self move assignment of standard containers was not allowed|after=allowed but the result is unspecified}}
 
{{dr list end}}
 
{{dr list end}}
  
 
{{langlinks|de|es|ja|ru|zh}}
 
{{langlinks|de|es|ja|ru|zh}}

Revision as of 14:07, 9 July 2023

 
 
C++ named requirements
 

An AllocatorAwareContainer is a Container that holds an instance of an Allocator and uses that instance in all its member functions to allocate and deallocate memory and to construct and destroy objects in that memory (such objects may be container elements, nodes, or, for unordered containers, bucket arrays), except that std::basic_string specializations do not use the allocators for construction/destruction of their elements(since C++23).

The following rules apply to container construction

  • Copy constructors of AllocatorAwareContainers obtain their instances of the allocator by calling std::allocator_traits<allocator_type>::select_on_container_copy_construction on the allocator of the container being copied.
  • Move constructors obtain their instances of allocators by move-constructing from the allocator belonging to the old container.
  • All other constructors take a const allocator_type& parameter.

The only way to replace an allocator is copy-assignment, move-assignment, and swap:

  • Copy-assignment will replace the allocator only if std::allocator_traits<allocator_type>::propagate_on_container_copy_assignment::value is true
  • Move-assignment will replace the allocator only if std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value is true
  • Swap will replace the allocator only if std::allocator_traits<allocator_type>::propagate_on_container_swap::value is true. Specifically, it will exchange the allocator instances through an unqualified call to the non-member function swap, see Swappable.

Note: swapping two containers with unequal allocators if propagate_on_container_swap is false is undefined behavior.

  • The accessor get_allocator() obtains a copy of the allocator that was used to construct the container or installed by the most recent allocator replacement operation.

Contents

Requirements

Legend

X Container type
T Element type
A Allocator for T
a, b Objects of type X (non-const lvalue)
t Object of type X (lvalue or const rvalue)
rv Object of type X (non-const rvalue)
m Object of type A

Types

Expression Return type Requirements
allocator_type A allocator_type::value_type must be the same as X::value_type

Member functions and operators

Expression Return type Pre/requirements Post/effects Complexity
get_allocator() A Constant
X u; A is DefaultConstructible u.empty() == true && u.get_allocator() == A() Constant
X u(m); u.empty() == true && u.get_allocator() == m Constant
X u(t,m); T is CopyInsertable into X u == t && u.get_allocator() == m Linear
X u(rv); Move constructor of A must not throw exceptions u has the same elements and an equal allocator as rv had before the construction Constant
X u(rv,m); T is MoveInsertable into X The elements of u are the same or copies of those of rv and u.get_allocator() == m Constant if m == rv.get_allocator(), otherwise linear
a = t X& T is CopyInsertable into X and CopyAssignable a == t Linear
a = rv X& If the allocator will not be replaced by move-assignment (see above), then T is MoveInsertable into X and MoveAssignable All existing elements of a are either move assigned to or destroyed; if a and rv do not refer the same object, a is equal to the value that rv had before the assignment Linear
a.swap(b) void Exchanges the contents of a and b Constant

Notes

Allocator-aware containers always call std::allocator_traits<A>::construct(m, p, args) to construct an object of type T at p using args, with m == get_allocator(). The default construct in std::allocator calls ::new((void*)p) T(args)(until C++20)std::allocator has no construct member and std::construct_at(p, args) is called when constructing elements(since C++20), but specialized allocators may choose a different definition

Standard library

All standard library containers except std::array are AllocatorAwareContainers:

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 2839 C++11 self move assignment of standard containers was not allowed allowed but the result is unspecified