# C++ named requirements: Allocator

From cppreference.com
< cpp‎ | named req

Encapsulates strategies for access/addressing, allocation/deallocation and construction/destruction of objects.

Every standard library component that may need to allocate or release storage, from `std::string`, `std::vector`, and every container except `std::array`, to `std::shared_ptr` and `std::function`, does so through an Allocator: an object of a class type that satisfies the following requirements.

Some requirements are optional: the template std::allocator_traits supplies the default implementations for all optional requirements, and all standard library containers and other allocator-aware classes access the allocator through `std::allocator_traits`, not directly.

### Requirements

Given

- `T`, a cv-unqualified object type
- `A`, an Allocator type for type `T`
- `a`, an object of type `A`
- `B`, the corresponding Allocator type for some cv-unqualified object type `U` (as obtained by rebinding `A`)
- `b`, an object of type `B`
- `ptr`, a value of type `allocator_traits<A>::pointer`, obtained by calling allocator_traits<A>::allocate()
- `cptr`, a value of type `allocator_traits<A>::const_pointer`, obtained by conversion from `ptr`
- `vptr`, a value of type `allocator_traits<A>::void_pointer`, obtained by conversion from `ptr`
- `cvptr`, a value of type `allocator_traits<A>::const_void_pointer`, obtained by conversion from `cptr` or from `vptr`
- `xptr`, a dereferencable pointer to some cv-unqualified object type `X`,
- `r`, an lvalue of type `T` obtained by the expression *ptr
- `n`, a value of type `allocator_traits<A>::size_type`

Expression | Requirements | Return type
--- | --- | ---
A::pointer (optional) | Satisfies NullablePointer, LegacyRandomAccessIterator, and LegacyContiguousIterator (see fancy pointers below) |
A::const_pointer (optional) | `A::pointer` is convertible to `A::const_pointer`. Satisfies NullablePointer, LegacyRandomAccessIterator, and LegacyContiguousIterator |
A::void_pointer (optional) | `A::pointer` is convertible to `A::void_pointer` `B::void_pointer` and `A::void_pointer` are the same type. Satisfies NullablePointer |
A::const_void_pointer (optional) | `A::pointer`, `A::const_pointer`, and `A::void_pointer` are convertible to `A::const_void_pointer` `B::const_void_pointer` and `A::const_void_pointer` are the same type. Satisfies NullablePointer |
A::value_type |  | the type `T`
A::size_type (optional) | `A::size_type` can represent the size of the largest object `A` can allocate | unsigned integer type
A::difference_type (optional) | `A::difference_type` can represent the difference of any two pointers to the objects allocated by `A` | signed integer type
A::template rebind<U>::other (optional)[1] | for any `U`, `B::template rebind<T>::other` is `A` | the type `B`
*ptr |  | `T&`
*cptr | *cptr and *ptr identify the same object | `const T&`
ptr->m | same as (*ptr).m, if (*ptr).m is well-defined | the type of `T::m`
cptr->m | same as (*cptr).m, if (*cptr).m is well-defined | the type of `T::m`
static_cast<A::pointer>(vptr) | static_cast<A::pointer>(vptr) == ptr | `A::pointer`
static_cast<A::const_pointer>(cvptr) | static_cast<A::const_pointer>(cvptr) == cptr | `A::const_pointer`
std::pointer_traits<A::pointer>::pointer_to(r) |  | `A::pointer`
a.allocate(n) | allocates storage suitable for `n` objects of type `T`, but does not construct them. May throw exceptions. | `A::pointer`
a.allocate(n, cvptr) (optional) | same as `a.allocate(n)`, but may use `cvptr` (a pointer obtained from `a.allocate()` or `nullptr_t`) in unspecified manner to aid locality | `A::pointer`
a.deallocate(ptr, n) | deallocates storage pointed to `ptr`, which must be a value returned by a previous call to allocate that has not been invalidated by an intervening call to `deallocate`. `n` must match the value previously passed to `allocate`. Does not throw exceptions. | (not used)
a.max_size() (optional) | the largest value that can be passed to `A::allocate()` | `A::size_type`
a1 == a2 | returns true only if the storage allocated by the allocator `a1` can be deallocated through `a2`. Establishes reflexive, symmetric, and transitive relationship. Does not throw exceptions. | bool
a1 != a2 | same as !(a1==a2) | bool
A a1(a) A a1 = a | Copy-constructs `a1` such that a1 == a. Does not throw exceptions. (Note: every Allocator also satisfies CopyConstructible) |
A a(b) | Constructs `a` such that B(a)==b and A(b)==a. Does not throw exceptions. (Note: this implies that all allocators related by rebind maintain each other's resources, such as memory pools) |
A a1(std::move(a)) A a1 = std::move(a) | Constructs `a1` such that it equals the prior value of `a`. Does not throw exceptions. The value of `a` is unchanged and a1 == a. (since C++20) |
A a(std::move(b)) | Constructs `a` such that it equals the prior value of `A(b)`. Does not throw exceptions. |
a.construct(xptr, args) (optional) | Constructs an object of type `X` in previously-allocated storage at the address pointed to by `xptr`, using args as the constructor arguments |
a.destroy(xptr) (optional) | Destructs an object of type `X` pointed to by `xptr`, but does not deallocate any storage. |
a.select_on_container_copy_construction() (optional) | Provides an instance of `A` to be used by the container that is copy-constructed from the one that uses `a` currently. Usually returns either a copy of `a` or a default-constructed `A()`. | `A`

A::propagate_on_container_copy_assignment (optional)

true if the allocator of type `A` needs to be copied when the container that uses it is copy-assigned. Note that if the allocators of the source and the target containers do not compare equal, copy assignment has to deallocate the target's memory using the old allocator and then allocate it using the new allocator before copying the elements (and the allocator).

std::true_type or std::false_type or derived from such

A::propagate_on_container_move_assignment (optional)

true if the allocator of type `A` needs to be moved when the container that uses it is move-assigned. If this member is false and the allocators of the source and the target containers do not compare equal, move assignment cannot take ownership of the source memory and must move-assign or move-construct the elements individually, resizing its own memory as needed.

std::true_type or std::false_type or derived from such

A::propagate_on_container_swap (optional) | true if the allocators of type `A` need to be swapped when two containers that use them are swapped. If this member is false and the allocators of the two containers do not compare equal, the behavior of container swap is undefined. | std::true_type or std::false_type or derived from such
A::is_always_equal (since C++17) (optional) | true if any two allocators of type `A` always compare equal. If not provided, std::allocator_traits defaults this to equal std::is_empty<A>::type | std::true_type or std::false_type or derived from such

Notes:

1. ↑ rebind is only optional (provided by std::allocator_traits) if this allocator is a template of the form SomeAllocator<T, Args>, where `Args` is zero or more additional template type parameters.

Additionally, in order for the type `A` to satisfy Allocator

- If `A::propagate_on_container_copy_assignment::value` is `true`, then `A` must satisfy CopyAssignable and the copy operation must not throw exceptions
- If `A::propagate_on_container_move_assignment::value` is `true`, then `A` must satisfy MoveAssignable and the move operation must not throw exceptions.
- If `A::propagate_on_container_swap::value` is `true`, lvalues of `A` must be Swappable and the swap operation must not throw exceptions

(since C++17)

Given

- `x1` and `x2`, 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

Given

- `w1` and `w2`, objects of type `X::void_pointer`.

Then for the expression w1 == w2 and 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.

Given

- `p1` and `p2`, 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.

The above requirements make it possible to compare Container's iterators and const_iterators.

(since C++14)

### Allocator completeness requirements

An allocator type `X` for type `T` additionally satisfies the allocator completeness requirements if both of the following are true regardless of whether `T` is a complete type:

- `X` is a complete type
- Except for `value_type`, all the member types of std::allocator_traits<X> are complete types.

(since C++17)

### Fancy pointers

When the member type `pointer` is not a raw pointer type, it is commonly referred to as a "fancy pointer". Such pointers were introduced to support segmented memory architectures and are used today to access objects allocated in address spaces that differ from the homogeneous virtual address space that is accessed by raw pointers. An example of a fancy pointer is the mapping address-independent pointer boost::interprocess::offset_ptr, which makes it possible to allocate node-based data structures such as std::set in shared memory and memory mapped files mapped in different addresses in every process. Fancy pointers can be used independently of the allocator that provided them, through the class template std::pointer_traits.

### Standard library

The following standard library components satisfy the Allocator requirements:

allocator | the default allocator (class template)
scoped_allocator_adaptor (C++11) | implements multi-level allocator for multi-level containers (class template)
polymorphic_allocator (C++17) | an allocator that supports run-time polymorphism based on the std::memory_resource it is constructed with (class template)

### Examples

A C++11 allocator, except for [[nodiscard]] added to match C++20 style

Run this code

    #include <cstdlib>
    #include <new>
    template <class T>
    struct Mallocator {
      typedef T value_type;
      Mallocator() = default;
      template <class U> constexpr Mallocator(const Mallocator<U>&) noexcept {}
      [[nodiscard]] T* allocate(std::size_t n) {
        if(n > std::size_t(-1) / sizeof(T)) throw std::bad_alloc();
        if(auto p = static_cast<T*>(std::malloc(n*sizeof(T)))) return p;
        throw std::bad_alloc();
      }
      void deallocate(T* p, std::size_t) noexcept { std::free(p); }
    };
    template <class T, class U>
    bool operator==(const Mallocator<T>&, const Mallocator<U>&) { return true; }
    template <class T, class U>
    bool operator!=(const Mallocator<T>&, const Mallocator<U>&) { return false; }

Retrieved from "https://en.cppreference.com/mwiki/index.php?title=cpp/named_req/Allocator&oldid=103869"