16 Library introduction [library]

16.4 Library-wide requirements [requirements]

16.4.4 Requirements on types and expressions [utility.requirements]

16.4.4.6 Cpp17Allocator requirements [allocator.requirements]

16.4.4.6.1 General [allocator.requirements.general]

The library describes a standard set of requirements for allocators, which are class-type objects that encapsulate the information about an allocation model.
This information includes the knowledge of pointer types, the type of their difference, the type of the size of objects in this allocation model, as well as the memory allocation and deallocation primitives for it.
All of the string types, containers (except array), string buffers and string streams ([input.output]), and match_­results are parameterized in terms of allocators.
In subclause [allocator.requirements],
  • T, U, C denote any cv-unqualified object type ([basic.types.general]),
  • X denotes an allocator class for type T,
  • Y denotes the corresponding allocator class for type U,
  • XX denotes the type allocator_­traits<X>,
  • YY denotes the type allocator_­traits<Y>,
  • a, a1, a2 denote lvalues of type X,
  • u denotes the name of a variable being declared,
  • b denotes a value of type Y,
  • c denotes a pointer of type C* through which indirection is valid,
  • p denotes a value of type XX​::​pointer obtained by calling a1.allocate, where a1 == a,
  • q denotes a value of type XX​::​const_­pointer obtained by conversion from a value p,
  • r denotes a value of type T& obtained by the expression *p,
  • w denotes a value of type XX​::​void_­pointer obtained by conversion from a value p,
  • x denotes a value of type XX​::​const_­void_­pointer obtained by conversion from a value q or a value w,
  • y denotes a value of type XX​::​const_­void_­pointer obtained by conversion from a result value of YY​::​allocate, or else a value of type (possibly const) std​::​nullptr_­t,
  • n denotes a value of type XX​::​size_­type,
  • Args denotes a template parameter pack, and
  • args denotes a function parameter pack with the pattern Args&&.
The class template allocator_­traits ([allocator.traits]) supplies a uniform interface to all allocator types.
This subclause describes the requirements on allocator types and thus on types used to instantiate allocator_­traits.
A requirement is optional if a default for a given type or expression is specified.
Within the standard library allocator_­traits template, an optional requirement that is not supplied by an allocator is replaced by the specified default type or expression.
A user specialization of allocator_­traits may provide different defaults and may provide defaults for different requirements than the primary template.
typename X::pointer
Remarks: Default: T*
typename X::const_pointer
Mandates: X​::​pointer is convertible to X​::​const_­pointer.
Remarks: Default: pointer_­traits<X​::​pointer>​::​rebind<const T>
typename X::void_pointer typename Y::void_pointer
Mandates: X​::​pointer is convertible to X​::​void_­pointer.
X​::​void_­pointer and Y​::​void_­pointer are the same type.
Remarks: Default: pointer_­traits<X​::​pointer>​::​rebind<void>
typename X::const_void_pointer typename Y::const_void_pointer
Mandates: X​::​pointer, X​::​const_­pointer, and X​::​void_­pointer are convertible to X​::​const_­void_­pointer.
X​::​const_­void_­pointer and Y​::​const_­void_­pointer are the same type.
Remarks: Default: pointer_­traits<X​::​pointer>​::​rebind<const void>
typename X::value_type
Result: Identical to T.
typename X::size_type
Result: An unsigned integer type that can represent the size of the largest object in the allocation model.
Remarks: Default: make_­unsigned_­t<X​::​difference_­type>
typename X::difference_type
Result: A signed integer type that can represent the difference between any two pointers in the allocation model.
Remarks: Default: pointer_­traits<X​::​pointer>​::​difference_­type
typename X::template rebind<U>::other
Result: Y
Postconditions: For all U (including T), Y​::​template rebind<T>​::​other is X.
Remarks: If Allocator is a class template instantiation of the form SomeAllocator<T, Args>, where Args is zero or more type arguments, and Allocator does not supply a rebind member template, the standard allocator_­traits template uses SomeAllocator<U, Args> in place of Allocator​::​rebind<U>​::​other by default.
For allocator types that are not template instantiations of the above form, no default is provided.
[Note 1:
The member class template rebind of X is effectively a typedef template.
In general, if the name Allocator is bound to SomeAllocator<T>, then Allocator​::​rebind<U>​::​other is the same type as SomeAllocator<U>, where SomeAllocator<T>​::​value_­type is T and SomeAllocator<U>​::​value_­type is U.
— end note]
*p
Result: T&
*q
Result: const T&
Postconditions: *q refers to the same object as *p.
p->m
Result: Type of T​::​m.
Preconditions: (*p).m is well-defined.
Effects: Equivalent to (*p).m.
q->m
Result: Type of T​::​m.
Preconditions: (*q).m is well-defined.
Effects: Equivalent to (*q).m.
static_cast<X::pointer>(w)
Result: X​::​pointer
Postconditions: static_­cast<X​::​pointer>(w) == p.
static_cast<X::const_pointer>(x)
Result: X​::​const_­pointer
Postconditions: static_­cast<X​::​const_­pointer>(x) == q.
pointer_traits<X::pointer>::pointer_to(r)
Result: X​::​pointer
Postconditions: Same as p.
a.allocate(n)
Result: X​::​pointer
Effects: Memory is allocated for an array of n T and such an object is created but array elements are not constructed.
[Example 1:
When reusing storage denoted by some pointer value p, launder(reinterpret_­cast<T*>(new (p) byte[n * sizeof(T)])) can be used to implicitly create a suitable array object and obtain a pointer to it.
— end example]
Throws: allocate may throw an appropriate exception.
[Note 2:
It is intended that a.allocate be an efficient means of allocating a single object of type T, even when sizeof(T) is small.
That is, there is no need for a container to maintain its own free list.
— end note]
Remarks: If n == 0, the return value is unspecified.
a.allocate(n, y)
Result: X​::​pointer
Effects: Same as a.allocate(n).
The use of y is unspecified, but it is intended as an aid to locality.
Remarks: Default: a.allocate(n)
a.allocate_at_least(n)
Result: allocation_­result<X​::​pointer>
Returns: allocation_­result<X​::​pointer>{ptr, count} where ptr is memory allocated for an array of count T and such an object is created but array elements are not constructed, such that .
If n == 0, the return value is unspecified.
Throws: allocate_­at_­least may throw an appropriate exception.
Remarks: An allocator need not support allocate_­at_­least, but no default is provided in allocator_­traits.
If an allocator has an allocate_­at_­least member, it shall satisfy the requirements.
a.deallocate(p, n)
Result: (not used)
Preconditions:
  • If p is memory that was obtained by a call to a.allocate_­at_­least, let ret be the value returned and req be the value passed as the first argument of that call.
    p is equal to ret.ptr and n is a value such that .
  • Otherwise, p is a pointer value obtained from allocate.
    n equals the value passed as the first argument to the invocation of allocate which returned p.
p has not been invalidated by an intervening call to deallocate.
Throws: Nothing.
a.max_size()
Result: X​::​size_­type
Returns: The largest value that can meaningfully be passed to X​::​allocate().
Remarks: Default: numeric_­limits<size_­type>​::​max() / sizeof(value_­type)
a1 == a2
Result: bool
Returns: true only if storage allocated from each can be deallocated via the other.
Throws: Nothing.
Remarks: operator== shall be reflexive, symmetric, and transitive.
a1 != a2
Result: bool
Returns: !(a1 == a2).
a == b
Result: bool
Returns: a == Y​::​rebind<T>​::​other(b).
a != b
Result: bool
Returns: !(a == b).
X u(a); X u = a;
Postconditions: u == a
Throws: Nothing.
X u(b);
Postconditions: Y(u) == b and u == X(b).
Throws: Nothing.
X u(std::move(a)); X u = std::move(a);
Postconditions: The value of a is unchanged and is equal to u.
Throws: Nothing.
X u(std::move(b));
Postconditions: u is equal to the prior value of X(b).
Throws: Nothing.
a.construct(c, args)
Result: (not used)
Effects: Constructs an object of type C at c.
Remarks: Default: construct_­at(c, std​::​forward<Args>(args)...)
a.destroy(c)
Result: (not used)
Effects: Destroys the object at c.
Remarks: Default: destroy_­at(c)
a.select_on_container_copy_construction()
Result: X
Returns: Typically returns either a or X().
Remarks: Default: return a;
X::propagate_on_container_copy_assignment
Result: Identical to or derived from true_­type or false_­type.
Returns: true_­type only if an allocator of type X should be copied when the client container is copy-assigned; if so, X shall meet the Cpp17CopyAssignable requirements (Table 33) and the copy operation shall not throw exceptions.
Remarks: Default: false_­type
X::propagate_on_container_move_assignment
Result: Identical to or derived from true_­type or false_­type.
Returns: true_­type only if an allocator of type X should be moved when the client container is move-assigned; if so, X shall meet the Cpp17MoveAssignable requirements (Table 32) and the move operation shall not throw exceptions.
Remarks: Default: false_­type
X::propagate_on_container_swap
Result: Identical to or derived from true_­type or false_­type.
Returns: true_­type only if an allocator of type X should be swapped when the client container is swapped; if so, lvalues of type X shall be swappable ([swappable.requirements]) and the swap operation shall not throw exceptions.
Remarks: Default: false_­type
X::is_always_equal
Result: Identical to or derived from true_­type or false_­type.
Returns: true_­type only if the expression a1 == a2 is guaranteed to be true for any two (possibly const) values a1, a2 of type X.
Remarks: Default: is_­empty<X>​::​type
An allocator type X shall meet the Cpp17CopyConstructible requirements (Table 31).
The X​::​pointer, X​::​const_­pointer, X​::​void_­pointer, and X​::​const_­void_­pointer types shall meet the Cpp17NullablePointer requirements (Table 35).
No constructor, comparison operator function, copy operation, move operation, or swap operation on these pointer types shall exit via an exception.
X​::​pointer and X​::​const_­pointer shall also meet the requirements for a Cpp17RandomAccessIterator ([random.access.iterators]) and the additional requirement that, when a and (a + n) are dereferenceable pointer values for some integral value n, addressof(*(a + n)) == addressof(*a) + n is true.
Let x1 and x2 denote objects of (possibly different) types X​::​void_­pointer, X​::​const_­void_­pointer, X​::​pointer, or X​::​const_­pointer.
Then, x1 and x2 are equivalently-valued pointer values, if and only if both x1 and x2 can be explicitly converted to the two corresponding objects px1 and px2 of type X​::​const_­pointer, using a sequence of static_­casts using only these four types, and the expression px1 == px2 evaluates to true.
Let w1 and w2 denote objects of type X​::​void_­pointer.
Then for the expressions w1 == w2 w1 != w2 either or both objects may be replaced by an equivalently-valued object of type X​::​const_­void_­pointer with no change in semantics.
Let p1 and p2 denote objects of type X​::​pointer.
Then for the expressions p1 == p2 p1 != p2 p1 < p2 p1 <= p2 p1 >= p2 p1 > p2 p1 - p2 either or both objects may be replaced by an equivalently-valued object of type X​::​const_­pointer with no change in semantics.
An allocator may constrain the types on which it can be instantiated and the arguments for which its construct or destroy members may be called.
If a type cannot be used with a particular allocator, the allocator class or the call to construct or destroy may fail to instantiate.
If the alignment associated with a specific over-aligned type is not supported by an allocator, instantiation of the allocator for that type may fail.
The allocator also may silently ignore the requested alignment.
[Note 3:
Additionally, the member function allocate for that type can fail by throwing an object of type bad_­alloc.
— end note]
[Example 2:
The following is an allocator class template supporting the minimal interface that meets the requirements of [allocator.requirements.general]: template<class Tp> struct SimpleAllocator { typedef Tp value_type; SimpleAllocator(ctor args); template<class T> SimpleAllocator(const SimpleAllocator<T>& other); [[nodiscard]] Tp* allocate(std::size_t n); void deallocate(Tp* p, std::size_t n); }; template<class T, class U> bool operator==(const SimpleAllocator<T>&, const SimpleAllocator<U>&); template<class T, class U> bool operator!=(const SimpleAllocator<T>&, const SimpleAllocator<U>&);
— end example]