24 Containers library [containers]

24.2 Requirements [container.requirements]

24.2.2 General containers [container.gen.reqmts]

24.2.2.5 Allocator-aware containers [container.alloc.reqmts]

All of the containers defined in [containers] and in [basic.string] except array meet the additional requirements of an allocator-aware container, as described below.
Given an allocator type A and given a container type X having a value_­type identical to T and an allocator_­type identical to allocator_­traits<A>​::​rebind_­alloc<T> and given an lvalue m of type A, a pointer p of type T*, an expression v of type T or const T, and an rvalue rv of type T, the following terms are defined.
If X is not allocator-aware or is a specialization of basic_­string, the terms below are defined as if A were allocator<T> — no allocator object needs to be created and user specializations of allocator<T> are not instantiated:
  • T is Cpp17DefaultInsertable into X means that the following expression is well-formed: allocator_traits<A>::construct(m, p)
  • An element of X is default-inserted if it is initialized by evaluation of the expression allocator_traits<A>::construct(m, p) where p is the address of the uninitialized storage for the element allocated within X.
  • T is Cpp17MoveInsertable into X means that the following expression is well-formed: allocator_traits<A>::construct(m, p, rv) and its evaluation causes the following postcondition to hold: The value of *p is equivalent to the value of rv before the evaluation.
    [Note 1:
    rv remains a valid object.
    Its state is unspecified
    — end note]
  • T is Cpp17CopyInsertable into X means that, in addition to T being Cpp17MoveInsertable into X, the following expression is well-formed: allocator_traits<A>::construct(m, p, v) and its evaluation causes the following postcondition to hold: The value of v is unchanged and is equivalent to *p.
  • T is Cpp17EmplaceConstructible into X from args, for zero or more arguments args, means that the following expression is well-formed: allocator_traits<A>::construct(m, p, args)
  • T is Cpp17Erasable from X means that the following expression is well-formed: allocator_traits<A>::destroy(m, p)
[Note 2:
A container calls allocator_­traits<A>​::​construct(m, p, args) to construct an element at p using args, with m == get_­allocator().
The default construct in allocator will call ​::​new((void*)p) T(args), but specialized allocators can choose a different definition.
— end note]
The following exposition-only concept is used in the definition of containers: template<class R, class T> concept container-compatible-range = // exposition only ranges::input_­range<R> && convertible_­to<ranges::range_reference_t<R>, T>;
In this subclause,
  • X denotes an allocator-aware container class with a value_­type of T using an allocator of type A,
  • u denotes a variable,
  • a and b denote non-const lvalues of type X,
  • c denotes an lvalue of type const X,
  • t denotes an lvalue or a const rvalue of type X,
  • rv denotes a non-const rvalue of type X, and
  • m is a value of type A.
A type X meets the allocator-aware container requirements if X meets the container requirements and the following types, statements, and expressions are well-formed and have the specified semantics.
typename X::allocator_type
Result: A
Preconditions: allocator_­type​::​value_­type is the same as X​::​value_­type.
c.get_allocator()
Result: A
Complexity: Constant.
X u; X u = X();
Preconditions: A meets the Cpp17DefaultConstructible requirements.
Postconditions: u.empty() returns true, u.get_­allocator() == A().
Complexity: Constant.
X u(m);
Postconditions: u.empty() returns true, u.get_­allocator() == m.
Complexity: Constant.
X u(t, m);
Preconditions: T is Cpp17CopyInsertable into X.
Postconditions: u == t, u.get_­allocator() == m
Complexity: Linear.
X u(rv);
Postconditions: u has the same elements as rv had before this construction; the value of u.get_­allocator() is the same as the value of rv.get_­allocator() before this construction.
Complexity: Constant.
X u(rv, m);
Preconditions: T is Cpp17MoveInsertable into X.
Postconditions: u has the same elements, or copies of the elements, that rv had before this construction, u.get_­allocator() == m.
Complexity: Constant if m == rv.get_­allocator(), otherwise linear.
a = t
Result: X&.
Preconditions: T is Cpp17CopyInsertable into X and Cpp17CopyAssignable.
Postconditions: a == t is true.
Complexity: Linear.
a = rv
Result: X&.
Preconditions: If allocator_­traits<allocator_­type>​::​propagate_­on_­container_­move_­assignment​::​value is false, T is Cpp17MoveInsertable into X and Cpp17MoveAssignable.
Effects: All existing elements of a are either move assigned to or destroyed.
Postconditions: If a and rv do not refer to the same object, a is equal to the value that rv had before this assignment.
Complexity: Linear.
a.swap(b)
Result: void
Effects: Exchanges the contents of a and b.
Complexity: Constant.
The behavior of certain container member functions and deduction guides depends on whether types qualify as input iterators or allocators.
The extent to which an implementation determines that a type cannot be an input iterator is unspecified, except that as a minimum integral types shall not qualify as input iterators.
Likewise, the extent to which an implementation determines that a type cannot be an allocator is unspecified, except that as a minimum a type A shall not qualify as an allocator unless it meets both of the following conditions:
  • The qualified-id A​::​value_­type is valid and denotes a type ([temp.deduct]).
  • The expression declval<A&>().allocate(size_­t{}) is well-formed when treated as an unevaluated operand.