23 General utilities library [utilities]

23.10 Memory [memory]

23.10.1 In general [memory.general]

В этом подпункте описывается содержимое заголовка <memory> и часть содержимого заголовка <cstdlib>.

23.10.2 Header <memory> synopsis [memory.syn]

Заголовок <memory> определяет несколько типов и шаблонов функций, которые описывают свойства указателей и типов, подобных указателям, управляют памятью для контейнеров и других типов шаблонов, уничтожают объекты и создают несколько объектов в неинициализированных буферах памяти ([pointer.traits]-[specialized.algorithms]). Заголовок также определяет шаблоны unique_­ptr, shared_­ptr, weak_­ptrшаблоны, и различные функции , которые работают на объектах этих типов ([smartptr]).

namespace std {
  // [pointer.traits], pointer traits
  template <class Ptr> struct pointer_traits;
  template <class T> struct pointer_traits<T*>;

  // [util.dynamic.safety], pointer safety
  enum class pointer_safety { relaxed, preferred, strict };
  void declare_reachable(void* p);
  template <class T> T* undeclare_reachable(T* p);
  void declare_no_pointers(char* p, size_t n);
  void undeclare_no_pointers(char* p, size_t n);
  pointer_safety get_pointer_safety() noexcept;

  // [ptr.align], pointer alignment function
  void* align(size_t alignment, size_t size, void*& ptr, size_t& space);

  // [allocator.tag], allocator argument tag
  struct allocator_arg_t { explicit allocator_arg_t() = default; };
  inline constexpr allocator_arg_t allocator_arg{};

  // [allocator.uses], uses_­allocator
  template <class T, class Alloc> struct uses_allocator;

  // [allocator.traits], allocator traits
  template <class Alloc> struct allocator_traits;

  // [default.allocator], the default allocator
  template <class T> class allocator;
  template <class T, class U>
    bool operator==(const allocator<T>&, const allocator<U>&) noexcept;
  template <class T, class U>
    bool operator!=(const allocator<T>&, const allocator<U>&) noexcept;

  // [specialized.algorithms], specialized algorithms
  template <class T> constexpr T* addressof(T& r) noexcept;
  template <class T> const T* addressof(const T&&) = delete;
  template <class ForwardIterator>
    void uninitialized_default_construct(ForwardIterator first, ForwardIterator last);
  template <class ExecutionPolicy, class ForwardIterator>
    void uninitialized_default_construct(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads]
                                         ForwardIterator first, ForwardIterator last);
  template <class ForwardIterator, class Size>
    ForwardIterator uninitialized_default_construct_n(ForwardIterator first, Size n);
  template <class ExecutionPolicy, class ForwardIterator, class Size>
    ForwardIterator uninitialized_default_construct_n(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads]
                                                      ForwardIterator first, Size n);
  template <class ForwardIterator>
    void uninitialized_value_construct(ForwardIterator first, ForwardIterator last);
  template <class ExecutionPolicy, class ForwardIterator>
    void uninitialized_value_construct(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads]
                                       ForwardIterator first, ForwardIterator last);
  template <class ForwardIterator, class Size>
    ForwardIterator uninitialized_value_construct_n(ForwardIterator first, Size n);
  template <class ExecutionPolicy, class ForwardIterator, class Size>
    ForwardIterator uninitialized_value_construct_n(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads]
                                                    ForwardIterator first, Size n);
  template <class InputIterator, class ForwardIterator>
    ForwardIterator uninitialized_copy(InputIterator first, InputIterator last,
                                       ForwardIterator result);
  template <class ExecutionPolicy, class InputIterator, class ForwardIterator>
    ForwardIterator uninitialized_copy(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads]
                                       InputIterator first, InputIterator last,
                                       ForwardIterator result);
  template <class InputIterator, class Size, class ForwardIterator>
    ForwardIterator uninitialized_copy_n(InputIterator first, Size n,
                                         ForwardIterator result);
  template <class ExecutionPolicy, class InputIterator, class Size, class ForwardIterator>
    ForwardIterator uninitialized_copy_n(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads]
                                         InputIterator first, Size n,
                                         ForwardIterator result);
  template <class InputIterator, class ForwardIterator>
    ForwardIterator uninitialized_move(InputIterator first, InputIterator last,
                                       ForwardIterator result);
  template <class ExecutionPolicy, class InputIterator, class ForwardIterator>
    ForwardIterator uninitialized_move(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads]
                                       InputIterator first, InputIterator last,
                                       ForwardIterator result);
  template <class InputIterator, class Size, class ForwardIterator>
    pair<InputIterator, ForwardIterator>
      uninitialized_move_n(InputIterator first, Size n, ForwardIterator result);
  template <class ExecutionPolicy, class InputIterator, class Size, class ForwardIterator>
    pair<InputIterator, ForwardIterator>
      uninitialized_move_n(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads]
                           InputIterator first, Size n, ForwardIterator result);
  template <class ForwardIterator, class T>
    void uninitialized_fill(ForwardIterator first, ForwardIterator last,
                            const T& x);
  template <class ExecutionPolicy, class ForwardIterator, class T>
    void uninitialized_fill(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads]
                            ForwardIterator first, ForwardIterator last,
                            const T& x);
  template <class ForwardIterator, class Size, class T>
    ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const T& x);
  template <class ExecutionPolicy, class ForwardIterator, class Size, class T>
    ForwardIterator uninitialized_fill_n(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads]
                                         ForwardIterator first, Size n, const T& x);
  template <class T>
    void destroy_at(T* location);
  template <class ForwardIterator>
    void destroy(ForwardIterator first, ForwardIterator last);
  template <class ExecutionPolicy, class ForwardIterator>
    void destroy(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads]
                 ForwardIterator first, ForwardIterator last);
  template <class ForwardIterator, class Size>
    ForwardIterator destroy_n(ForwardIterator first, Size n);
  template <class ExecutionPolicy, class ForwardIterator, class Size>
    ForwardIterator destroy_n(ExecutionPolicy&& exec, // see [algorithms.parallel.overloads]
                              ForwardIterator first, Size n);

  // [unique.ptr], class template unique_­ptr
  template <class T> struct default_delete;
  template <class T> struct default_delete<T[]>;
  template <class T, class D = default_delete<T>> class unique_ptr;
  template <class T, class D> class unique_ptr<T[], D>;

  template <class T, class... Args> unique_ptr<T> make_unique(Args&&... args);
  template <class T> unique_ptr<T> make_unique(size_t n);
  template <class T, class... Args> unspecified make_unique(Args&&...) = delete;

  template <class T, class D> void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y) noexcept;

  template <class T1, class D1, class T2, class D2>
    bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
  template <class T1, class D1, class T2, class D2>
    bool operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
  template <class T1, class D1, class T2, class D2>
    bool operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
  template <class T1, class D1, class T2, class D2>
    bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
  template <class T1, class D1, class T2, class D2>
    bool operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);
  template <class T1, class D1, class T2, class D2>
    bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);

  template <class T, class D>
    bool operator==(const unique_ptr<T, D>& x, nullptr_t) noexcept;
  template <class T, class D>
    bool operator==(nullptr_t, const unique_ptr<T, D>& y) noexcept;
  template <class T, class D>
    bool operator!=(const unique_ptr<T, D>& x, nullptr_t) noexcept;
  template <class T, class D>
    bool operator!=(nullptr_t, const unique_ptr<T, D>& y) noexcept;
  template <class T, class D>
    bool operator<(const unique_ptr<T, D>& x, nullptr_t);
  template <class T, class D>
    bool operator<(nullptr_t, const unique_ptr<T, D>& y);
  template <class T, class D>
    bool operator<=(const unique_ptr<T, D>& x, nullptr_t);
  template <class T, class D>
    bool operator<=(nullptr_t, const unique_ptr<T, D>& y);
  template <class T, class D>
    bool operator>(const unique_ptr<T, D>& x, nullptr_t);
  template <class T, class D>
    bool operator>(nullptr_t, const unique_ptr<T, D>& y);
  template <class T, class D>
    bool operator>=(const unique_ptr<T, D>& x, nullptr_t);
  template <class T, class D>
    bool operator>=(nullptr_t, const unique_ptr<T, D>& y);

  // [util.smartptr.weak.bad], class bad_­weak_­ptr
  class bad_weak_ptr;

  // [util.smartptr.shared], class template shared_­ptr
  template<class T> class shared_ptr;

  // [util.smartptr.shared.create], shared_­ptr creation
  template<class T, class... Args>
    shared_ptr<T> make_shared(Args&&... args);
  template<class T, class A, class... Args>
    shared_ptr<T> allocate_shared(const A& a, Args&&... args);

  // [util.smartptr.shared.cmp], shared_­ptr comparisons
  template<class T, class U>
    bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept;
  template<class T, class U>
    bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept;
  template<class T, class U>
    bool operator<(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept;
  template<class T, class U>
    bool operator>(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept;
  template<class T, class U>
    bool operator<=(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept;
  template<class T, class U>
    bool operator>=(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept;

  template <class T>
    bool operator==(const shared_ptr<T>& x, nullptr_t) noexcept;
  template <class T>
    bool operator==(nullptr_t, const shared_ptr<T>& y) noexcept;
  template <class T>
    bool operator!=(const shared_ptr<T>& x, nullptr_t) noexcept;
  template <class T>
    bool operator!=(nullptr_t, const shared_ptr<T>& y) noexcept;
  template <class T>
    bool operator<(const shared_ptr<T>& x, nullptr_t) noexcept;
  template <class T>
    bool operator<(nullptr_t, const shared_ptr<T>& y) noexcept;
  template <class T>
    bool operator<=(const shared_ptr<T>& x, nullptr_t) noexcept;
  template <class T>
    bool operator<=(nullptr_t, const shared_ptr<T>& y) noexcept;
  template <class T>
    bool operator>(const shared_ptr<T>& x, nullptr_t) noexcept;
  template <class T>
    bool operator>(nullptr_t, const shared_ptr<T>& y) noexcept;
  template <class T>
    bool operator>=(const shared_ptr<T>& x, nullptr_t) noexcept;
  template <class T>
    bool operator>=(nullptr_t, const shared_ptr<T>& y) noexcept;

  // [util.smartptr.shared.spec], shared_­ptr specialized algorithms
  template<class T>
    void swap(shared_ptr<T>& a, shared_ptr<T>& b) noexcept;

  // [util.smartptr.shared.cast], shared_­ptr casts
  template<class T, class U>
    shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r) noexcept;
  template<class T, class U>
    shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& r) noexcept;
  template<class T, class U>
    shared_ptr<T> const_pointer_cast(const shared_ptr<U>& r) noexcept;

  // [util.smartptr.getdeleter], shared_­ptr get_­deleter
  template<class D, class T>
    D* get_deleter(const shared_ptr<T>& p) noexcept;

  // [util.smartptr.shared.io], shared_­ptr I/O
  template<class E, class T, class Y>
    basic_ostream<E, T>& operator<< (basic_ostream<E, T>& os, const shared_ptr<Y>& p);

  // [util.smartptr.weak], class template weak_­ptr
  template<class T> class weak_ptr;

  // [util.smartptr.weak.spec], weak_­ptr specialized algorithms
  template<class T> void swap(weak_ptr<T>& a, weak_ptr<T>& b) noexcept;

  // [util.smartptr.ownerless], class template owner_­less
  template<class T = void> struct owner_less;

  // [util.smartptr.enab], class template enable_­shared_­from_­this
  template<class T> class enable_shared_from_this;

  // [util.smartptr.shared.atomic], shared_­ptr atomic access
  template<class T>
    bool atomic_is_lock_free(const shared_ptr<T>* p);

  template<class T>
    shared_ptr<T> atomic_load(const shared_ptr<T>* p);
  template<class T>
    shared_ptr<T> atomic_load_explicit(const shared_ptr<T>* p, memory_order mo);

  template<class T>
    void atomic_store(shared_ptr<T>* p, shared_ptr<T> r);
  template<class T>
    void atomic_store_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);

  template<class T>
    shared_ptr<T> atomic_exchange(shared_ptr<T>* p, shared_ptr<T> r);
  template<class T>
    shared_ptr<T> atomic_exchange_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);

  template<class T>
    bool atomic_compare_exchange_weak(
      shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);
  template<class T>
    bool atomic_compare_exchange_strong(
      shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);
  template<class T>
    bool atomic_compare_exchange_weak_explicit(
      shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w,
      memory_order success, memory_order failure);
  template<class T>
    bool atomic_compare_exchange_strong_explicit(
      shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w,
      memory_order success, memory_order failure);

  // [util.smartptr.hash], hash support
  template <class T> struct hash;
  template <class T, class D> struct hash<unique_ptr<T, D>>;
  template <class T> struct hash<shared_ptr<T>>;

  // [allocator.uses.trait], uses_­allocator
  template <class T, class Alloc>
    inline constexpr bool uses_allocator_v = uses_allocator<T, Alloc>::value;
}

23.10.3 Pointer traits [pointer.traits]

Шаблон класса pointer_­traits предоставляет единый интерфейс для определенных атрибутов типов, подобных указателям.

namespace std {
  template <class Ptr> struct pointer_traits {
    using pointer         = Ptr;
    using element_type    = see below;
    using difference_type = see below;

    template <class U> using rebind = see below;

    static pointer pointer_to(see below r);
  };

  template <class T> struct pointer_traits<T*> {
    using pointer         = T*;
    using element_type    = T;
    using difference_type = ptrdiff_t;

    template <class U> using rebind = U*;

    static pointer pointer_to(see below r) noexcept;
  };
}

23.10.3.1 Pointer traits member types [pointer.traits.types]

using element_type = see below;

Type: Ptr​::​element_­type если qualified-id Ptr​::​element_­type действительный и обозначает тип ([temp.deduct]); в противном случае, T if Ptr является экземпляром формы шаблона класса SomePointer<T, Args>, где Args - ноль или более аргументов типа; в противном случае специализация сформирована неправильно.

using difference_type = see below;

Type: Ptr​::​difference_­type если qualified-id Ptr​::​difference_­type действительный и обозначает тип ([temp.deduct]); в противном случае ptrdiff_­t.

template <class U> using rebind = see below;

Alias template: Ptr​::​rebind<U> если qualified-id Ptr​::​rebind<U> действительный и обозначает тип ([temp.deduct]); в противном случае, SomePointer<U, Args> if Ptr является экземпляром формы шаблона класса SomePointer<T, Args>, где Args - ноль или более аргументов типа; в противном случае создание экземпляра rebind будет некорректным.

23.10.3.2 Pointer traits member functions [pointer.traits.functions]

static pointer pointer_traits::pointer_to(see below r); static pointer pointer_traits<T*>::pointer_to(see below r) noexcept;

Remarks: Если element_­type есть cv void, то тип r не указан; в противном случае это так element_­type&.

Returns: Первая функция-член возвращает указатель на r полученный путем вызова, Ptr​::​pointer_­to(r) через который допустимо косвенное обращение ; экземпляр этой функции плохо сформирован, если Ptr не имеет соответствующей pointer_­to статической функции-члена. Вторая функция-член возвращается addressof(r).

23.10.4 Pointer safety [util.dynamic.safety]

Полный объект - это declared reachable когда количество вызовов declare_­reachable с аргументом, ссылающимся на объект, превышает количество вызовов undeclare_­reachable с аргументом, ссылающимся на объект.

void declare_reachable(void* p);

Requires: p должен быть значением safely-derived pointer или нулевым указателем.

Effects: Если p не равно нулю, то весь объект, на который ссылается, p впоследствии объявляется достижимым ([basic.stc.dynamic.safety]).

Throws: bad_­alloc Может вызвать ошибку, если система не может выделить дополнительную память, которая может потребоваться для отслеживания объектов, объявленных достижимыми.

template <class T> T* undeclare_reachable(T* p);

Requires: Если p не равно нулю, весь объект, на который ссылается, p должен быть ранее объявлен достижимым и должен быть live ([basic.life]) с момента вызова до последнего undeclare_­reachable(p) вызова объекта.

Returns: Безопасно полученная копия, p которая будет сравниваться с p.

Throws: Ничего такого.

[ Note: Ожидается, что вызовы to declare_­reachable(p) будут потреблять небольшой объем памяти в дополнение к памяти, занятой объектом, на который указывает ссылка, до тех пор, пока не будет обнаружен соответствующий вызов undeclare_­reachable(p) . Долгосрочные программы должны согласовывать вызовы. ] end note

void declare_no_pointers(char* p, size_t n);

Requires: В настоящее время не зарегистрированы байты в указанном диапазоне declare_­no_­pointers(). Если указанный диапазон находится в выделенном объекте, то он должен полностью находиться в пределах одного выделенного объекта. Объект должен быть жив до соответствующего undeclare_­no_­pointers() звонка. [ Note: В реализации сборки мусора тот факт, что область в объекте регистрируется, declare_­no_­pointers() не должен препятствовать сборке объекта. ] end note

Effects: В n байтах , начиная с p уже не содержат отслеживаемые местоположения указателя, независимо от их типа. Следовательно, косвенное обращение через указатель, расположенный там, не определено, если объект, на который он указывает, был создан глобальным operator new и ранее не объявлен достижимым. [ Note: Это может быть использовано для информирования сборщика мусора или детектора утечек о том, что эту область памяти не нужно отслеживать. ] end note

Throws: Ничего такого.

[ Note: В некоторых случаях реализациям может потребоваться выделить память. Однако в случае сбоя выделения памяти запрос можно проигнорировать. ] end note

void undeclare_no_pointers(char* p, size_t n);

Requires: Тот же диапазон должен быть ранее передан declare_­no_­pointers().

Effects: Отменяет регистрацию диапазона, зарегистрированного declare_­no_­pointers() для уничтожения. Он должен быть вызван до того, как закончится время жизни объекта.

Throws: Ничего такого.

pointer_safety get_pointer_safety() noexcept;

Returns: pointer_­safety​::​strict если в реализации есть strict pointer safety. Это определяется реализацией ли get_­pointer_­safety возвращается pointer_­safety​::​relaxed или ,pointer_­safety​::​preferred если реализация имеет непринужденную безопасность указателя.221

pointer_­safety​::​preferred может быть возвращено, чтобы указать, что течеискатель работает, чтобы программа могла избежать ложных отчетов об утечках.

23.10.5 Align [ptr.align]

void* align(size_t alignment, size_t size, void*& ptr, size_t& space);

Effects: Если возможно уместить size байты хранилища, выровненного по, alignment в буфер, на который указывает ptr длина space, функция обновляется, ptr чтобы представить первый возможный адрес такого хранилища, и уменьшается space на количество байтов, используемых для выравнивания. В противном случае функция ничего не делает.

Requires:

  • alignment будет степенью двойки

  • ptr представляет собой адрес непрерывного хранения не менее space байтов

Returns: Нулевой указатель, если запрошенный выровненный буфер не помещается в доступное пространство, в противном случае скорректированное значение ptr.

[ Note: Функция обновляет свои ptr и space аргументы , так что его можно назвать несколько раз , возможно , с разными alignment и size аргументы для того же буфера. ] end note

23.10.6 Allocator argument tag [allocator.tag]

namespace std { struct allocator_arg_t { explicit allocator_arg_t() = default; }; inline constexpr allocator_arg_t allocator_arg{}; }

Структура allocator_­arg_­t - это пустой тип структуры, используемый как уникальный тип для устранения неоднозначности перегрузки конструктора и функции. В частности, несколько типов (см. tuple [tuple]) Имеют конструкторы с allocator_­arg_­t первым аргументом, за которым сразу следует аргумент типа, удовлетворяющего Allocator требованиям.

23.10.7 uses_­allocator [allocator.uses]

23.10.7.1 uses_­allocator trait [allocator.uses.trait]

template <class T, class Alloc> struct uses_allocator;

Remarks: Автоматически определяет, T есть ли вложенный allocator_­type конвертируемый из Alloc. Отвечает BinaryTypeTrait требованиям. Реализация должна обеспечивать определение, производное от true_­type того, qualified-id T​::​allocator_­type является ли действительным и обозначает тип ([temp.deduct]), а в is_­convertible_­v<Alloc, T​::​allocator_­type> != falseпротивном случае оно должно быть производным от false_­type. Программа может специализировать этот шаблон, чтобы он производился от true_­type определяемого пользователем типа T , который не имеет вложенного, allocator_­type но, тем не менее, может быть создан с помощью распределителя, где либо:

  • первый аргумент конструктора имеет тип, allocator_­arg_­t а второй аргумент имеет тип Alloc или

  • последний аргумент конструктора имеет тип Alloc.

23.10.7.2 Uses-allocator construction [allocator.uses.construction]

Uses-allocator construction с распределителем Alloc относится к построению объекта obj типа Tс использованием аргументов v1, v2, ..., vN конструктора типов V1, V2, ..., VNсоответственно и распределителя alloc типа в Allocсоответствии со следующими правилами:

  • если uses_­allocator_­v<T, Alloc> есть false и is_­constructible_­v<T, V1, V2, ..., VN> есть true, то obj инициализируется как obj(v1, v2, ..., vN);

  • в противном случае, если uses_­allocator_­v<T, Alloc> есть true и is_­constructible_­v<T, allocator_­arg_­t, Alloc, V1, V2, ..., VN> есть true, то obj инициализируется как obj(allocator_­arg, alloc, v1, v2, ..., vN);

  • в противном случае, если uses_­allocator_­v<T, Alloc> есть true и is_­constructible_­v<T, V1, V2, ..., VN, Alloc> есть true, то obj инициализируется как obj(v1, v2, ..., vN, alloc);

  • в противном случае запрос на построение распределителя использования будет некорректным. [ Note: Произойдет ошибка, если uses_­allocator_­v<T, Alloc> есть, true но конкретный конструктор не использует распределитель. Это определение предотвращает тихую ошибку передачи распределителя элементу. ] end note

23.10.8 Allocator traits [allocator.traits]

Шаблон класса allocator_­traits предоставляет единый интерфейс для всех типов распределителей. Однако распределитель не может быть неклассовым типом, даже если allocator_­traits предоставляет весь требуемый интерфейс. [ Note: Таким образом, всегда можно создать производный класс из распределителя. ] end note

namespace std {
  template <class Alloc> struct allocator_traits {
    using allocator_type     = Alloc;

    using value_type         = typename Alloc::value_type;

    using pointer            = see below;
    using const_pointer      = see below;
    using void_pointer       = see below;
    using const_void_pointer = see below;

    using difference_type    = see below;
    using size_type          = see below;

    using propagate_on_container_copy_assignment = see below;
    using propagate_on_container_move_assignment = see below;
    using propagate_on_container_swap            = see below;
    using is_always_equal                        = see below;

    template <class T> using rebind_alloc = see below;
    template <class T> using rebind_traits = allocator_traits<rebind_alloc<T>>;

    static pointer allocate(Alloc& a, size_type n);
    static pointer allocate(Alloc& a, size_type n, const_void_pointer hint);

    static void deallocate(Alloc& a, pointer p, size_type n);

    template <class T, class... Args>
      static void construct(Alloc& a, T* p, Args&&... args);

    template <class T>
      static void destroy(Alloc& a, T* p);

    static size_type max_size(const Alloc& a) noexcept;

    static Alloc select_on_container_copy_construction(const Alloc& rhs);
  };
}

23.10.8.1 Allocator traits member types [allocator.traits.types]

using pointer = see below;

Type: Alloc​::​pointer если qualified-id Alloc​::​pointer действительный и обозначает тип ([temp.deduct]); в противном случае value_­type*.

using const_pointer = see below;

Type: Alloc​::​const_­pointer если qualified-id Alloc​::​const_­pointer действительный и обозначает тип ([temp.deduct]); в противном случае pointer_­traits<pointer>​::​rebind<​const value_­type>.

using void_pointer = see below;

Type: Alloc​::​void_­pointer если qualified-id Alloc​::​void_­pointer действительный и обозначает тип ([temp.deduct]); в противном случае pointer_­traits<pointer>​::​rebind<​void>.

using const_void_pointer = see below;

Type: Alloc​::​const_­void_­pointer если qualified-id Alloc​::​const_­void_­pointer действительный и обозначает тип ([temp.deduct]); в противном случае pointer_­traits<pointer>​::​​rebind<const void>.

using difference_type = see below;

Type: Alloc​::​difference_­type если qualified-id Alloc​::​difference_­type действительный и обозначает тип ([temp.deduct]); в противном случае pointer_­traits<pointer>​::​difference_­type.

using size_type = see below;

Type: Alloc​::​size_­type если qualified-id Alloc​::​size_­type действительный и обозначает тип ([temp.deduct]); в противном случае make_­unsigned_­t<difference_­type>.

using propagate_on_container_copy_assignment = see below;

Type: Alloc​::​propagate_­on_­container_­copy_­assignment если qualified-id Alloc​::​propagate_­on_­container_­copy_­assignment действительный и обозначает тип ([temp.deduct]); иначе false_­type.

using propagate_on_container_move_assignment = see below;

Type: Alloc​::​propagate_­on_­container_­move_­assignment если qualified-id Alloc​::​propagate_­on_­container_­move_­assignment действительный и обозначает тип ([temp.deduct]); иначе false_­type.

using propagate_on_container_swap = see below;

Type: Alloc​::​propagate_­on_­container_­swap если qualified-id Alloc​::​propagate_­on_­container_­swap действительный и обозначает тип ([temp.deduct]); иначе false_­type.

using is_always_equal = see below;

Type: Alloc​::​is_­always_­equal если qualified-id Alloc​::​is_­always_­equal действительный и обозначает тип ([temp.deduct]); иначе is_­empty<Alloc>​::​type.

template <class T> using rebind_alloc = see below;

Alias template: Alloc​::​rebind<T>​::​other если qualified-id Alloc​::​rebind<T>​::​other действительный и обозначает тип ([temp.deduct]); в противном случае, Alloc<T, Args> if Alloc является экземпляром формы шаблона класса Alloc<U, Args>, где Args - ноль или более аргументов типа; в противном случае создание экземпляра rebind_­alloc будет некорректным.

23.10.8.2 Allocator traits static member functions [allocator.traits.members]

static pointer allocate(Alloc& a, size_type n);

Returns: a.allocate(n).

static pointer allocate(Alloc& a, size_type n, const_void_pointer hint);

Returns: a.allocate(n, hint) если это выражение правильно сформировано; в противном случае a.allocate(n).

static void deallocate(Alloc& a, pointer p, size_type n);

Effects: Звонки a.deallocate(p, n).

Throws: Ничего такого.

template <class T, class... Args> static void construct(Alloc& a, T* p, Args&&... args);

Effects: Звонит, a.construct(p, std​::​forward<Args>(args)...) если этот звонок правильно сформирован; в противном случае вызывает ​::​new (static_­cast<void*>(p)) T(std​::​forward<Args>(args)...).

template <class T> static void destroy(Alloc& a, T* p);

Effects: Звонит, a.destroy(p) если этот звонок правильно сформирован; в противном случае вызывает p->~T().

static size_type max_size(const Alloc& a) noexcept;

Returns: a.max_­size() если это выражение правильно сформировано; в противном случае numeric_­limits<size_­type>​::​​max()/sizeof(value_­type).

static Alloc select_on_container_copy_construction(const Alloc& rhs);

Returns: rhs.select_­on_­container_­copy_­construction() если это выражение правильно сформировано; в противном случае rhs.

23.10.9 The default allocator [default.allocator]

Все специализации распределителя по умолчанию удовлетворяют требованиям полноты распределителя ([allocator.requirements.completeness]).

namespace std {
  template <class T> class allocator {
   public:
    using value_type      = T;
    using propagate_on_container_move_assignment = true_type;
    using is_always_equal = true_type;

    allocator() noexcept;
    allocator(const allocator&) noexcept;
    template <class U> allocator(const allocator<U>&) noexcept;
    ~allocator();

    T* allocate(size_t n);
    void deallocate(T* p, size_t n);
  };
}

23.10.9.1 allocator members [allocator.members]

За исключением деструктора, функции-члены распределителя по умолчанию не должны вводиться data races в результате одновременных вызовов этих функций-членов из разных потоков. Вызов этих функций, которые выделяют или освобождают конкретную единицу памяти, должны происходить в едином общем порядке, и каждый такой вызов освобождения должен происходить до следующего выделения (если таковое имеется) в этом порядке.

T* allocate(size_t n);

Returns: Указатель на начальный элемент массива хранения размера n * sizeof(T), выровненный соответствующим образом для объектов типа T.

Remarks: хранилище получается путем вызова ​::​operator new, но не указано, когда и как часто вызывается эта функция.

Throws: bad_­alloc если невозможно получить хранилище.

void deallocate(T* p, size_t n);

Requires: p должно быть значением указателя, полученным из allocate(). n должен быть равен значению, переданному в качестве первого аргумента при вызове функции allocate, которая вернулась p.

Effects: Освобождает хранилище, на которое ссылается p .

Remarks: Используется ​::​operator delete, но не указывается при вызове этой функции.

23.10.9.2 allocator globals [allocator.globals]

template <class T, class U> bool operator==(const allocator<T>&, const allocator<U>&) noexcept;

Returns: true.

template <class T, class U> bool operator!=(const allocator<T>&, const allocator<U>&) noexcept;

Returns: false.

23.10.10 Specialized algorithms [specialized.algorithms]

В этом подпункте имена параметров шаблона используются для выражения требований к типу.

  • Если указан параметр шаблона алгоритма InputIterator, аргумент шаблона должен удовлетворять требованиям input iterator.

  • Если параметр шаблона алгоритма назван ForwardIterator, аргумент шаблона должен удовлетворять требованиям a forward iteratorи должен иметь свойство, согласно которому исключения не генерируются при увеличении, назначении, сравнении или косвенном обращении через допустимые итераторы.

Если не указано иное, если в следующих алгоритмах возникает исключение, никаких эффектов не возникает.

23.10.10.1 addressof [specialized.addressof]

template <class T> constexpr T* addressof(T& r) noexcept;

Returns: Фактический адрес объекта или функции, на которые ссылается r, даже при наличии перегруженного operator&.

Remarks: Выражение addressof(E) - это constant subexpression if E - подвыражение константы lvalue.

23.10.10.2 uninitialized_­default_­construct [uninitialized.construct.default]

template <class ForwardIterator> void uninitialized_default_construct(ForwardIterator first, ForwardIterator last);

Effects: Эквивалентен:

for (; first != last; ++first)
  ::new (static_cast<void*>(addressof(*first)))
    typename iterator_traits<ForwardIterator>::value_type;

template <class ForwardIterator, class Size> ForwardIterator uninitialized_default_construct_n(ForwardIterator first, Size n);

Effects: Эквивалентен:

for (; n>0; (void)++first, --n)
  ::new (static_cast<void*>(addressof(*first)))
    typename iterator_traits<ForwardIterator>::value_type;
return first;

23.10.10.3 uninitialized_­value_­construct [uninitialized.construct.value]

template <class ForwardIterator> void uninitialized_value_construct(ForwardIterator first, ForwardIterator last);

Effects: Эквивалентен:

for (; first != last; ++first)
  ::new (static_cast<void*>(addressof(*first)))
    typename iterator_traits<ForwardIterator>::value_type();

template <class ForwardIterator, class Size> ForwardIterator uninitialized_value_construct_n(ForwardIterator first, Size n);

Effects: Эквивалентен:

for (; n>0; (void)++first, --n)
  ::new (static_cast<void*>(addressof(*first)))
    typename iterator_traits<ForwardIterator>::value_type();
return first;

23.10.10.4 uninitialized_­copy [uninitialized.copy]

template <class InputIterator, class ForwardIterator> ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator result);

Effects: Как будто по:

for (; first != last; ++result, (void) ++first)
  ::new (static_cast<void*>(addressof(*result)))
    typename iterator_traits<ForwardIterator>::value_type(*first);

Returns: result.

template <class InputIterator, class Size, class ForwardIterator> ForwardIterator uninitialized_copy_n(InputIterator first, Size n, ForwardIterator result);

Effects: Как будто по:

for ( ; n > 0; ++result, (void) ++first, --n) {
  ::new (static_cast<void*>(addressof(*result)))
    typename iterator_traits<ForwardIterator>::value_type(*first);
}

Returns: result.

23.10.10.5 uninitialized_­move [uninitialized.move]

template <class InputIterator, class ForwardIterator> ForwardIterator uninitialized_move(InputIterator first, InputIterator last, ForwardIterator result);

Effects: Эквивалентен:

for (; first != last; (void)++result, ++first)
  ::new (static_cast<void*>(addressof(*result)))
    typename iterator_traits<ForwardIterator>::value_type(std::move(*first));
return result;

Remarks: Если выбрасывается исключение, некоторые объекты в диапазоне [first, last) остаются в допустимом, но неуказанном состоянии.

template <class InputIterator, class Size, class ForwardIterator> pair<InputIterator, ForwardIterator> uninitialized_move_n(InputIterator first, Size n, ForwardIterator result);

Effects: Эквивалентен:

for (; n > 0; ++result, (void) ++first, --n)
  ::new (static_cast<void*>(addressof(*result)))
    typename iterator_traits<ForwardIterator>::value_type(std::move(*first));
return {first,result};

Remarks: Если выбрасывается исключение, некоторые объекты в диапазоне [first, std​::​next(first,n)) остаются в допустимом, но неуказанном состоянии.

23.10.10.6 uninitialized_­fill [uninitialized.fill]

template <class ForwardIterator, class T> void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& x);

Effects: Как будто по:

for (; first != last; ++first)
  ::new (static_cast<void*>(addressof(*first)))
    typename iterator_traits<ForwardIterator>::value_type(x);

template <class ForwardIterator, class Size, class T> ForwardIterator uninitialized_fill_n(ForwardIterator first, Size n, const T& x);

Effects: Как будто по:

for (; n--; ++first)
  ::new (static_cast<void*>(addressof(*first)))
    typename iterator_traits<ForwardIterator>::value_type(x);
return first;

23.10.10.7 destroy [specialized.destroy]

template <class T> void destroy_at(T* location);

Effects: Эквивалентен:

location->~T();

template <class ForwardIterator> void destroy(ForwardIterator first, ForwardIterator last);

Effects: Эквивалентен:

for (; first!=last; ++first)
  destroy_at(addressof(*first));
template <class ForwardIterator, class Size> ForwardIterator destroy_n(ForwardIterator first, Size n);

Effects: Эквивалентен:

for (; n > 0; (void)++first, --n)
  destroy_at(addressof(*first));
return first;

23.10.11 C library memory allocation [c.malloc]

[ Note: Заголовок <cstdlib> объявляет функции, описанные в этом подпункте. ]end note

void* aligned_­alloc(size_t alignment, size_t size); void* calloc(size_t nmemb, size_t size); void* malloc(size_t size); void* realloc(void* ptr, size_t size);

Effects: Эти функции имеют семантику, указанную в стандартной библиотеке C.

Remarks: Эти функции не пытаются выделить память с помощью вызова ​::​operator new() ([support.dynamic]).

Хранилище, выделенное непосредственно с помощью этих функций, неявно объявляется доступным (см. [basic.stc.dynamic.safety]) При выделении, перестает объявляться доступным при освобождении и не обязательно перестает объявляться доступным в результате undeclare_­reachable() вызова. [ Note: Это позволяет существующим библиотекам C оставаться незатронутыми ограничениями на указатели, которые не извлекаются безопасно, за счет предоставления гораздо меньшего количества вариантов сборки мусора и обнаружения утечек для malloc()-распределенных объектов. Это также позволяет malloc() реализовать с отдельной ареной распределения, минуя обычную declare_­reachable() реализацию. Вышеупомянутые функции никогда не должны преднамеренно использоваться в качестве замены declare_­reachable(), и вновь написанный код настоятельно рекомендуется обрабатывать память, выделенную этими функциями, как если бы она была выделена с помощью operator new. ] end note

void free(void* ptr);

Effects: Эта функция имеет семантику, указанную в стандартной библиотеке C.

Remarks: Эта функция не пытается освободить память путем вызова . ​::​operator delete()

См. Также: ISO C 7.22.3.