23 General utilities library [utilities]

23.12 Memory resources [mem.res]

23.12.1 Header <memory_­resource> synopsis [mem.res.syn]

namespace std::pmr {
  // [mem.res.class], class memory_­resource
  class memory_resource;

  bool operator==(const memory_resource& a, const memory_resource& b) noexcept;
  bool operator!=(const memory_resource& a, const memory_resource& b) noexcept;

  // [mem.poly.allocator.class], class template polymorphic_­allocator
  template <class Tp> class polymorphic_allocator;

  template <class T1, class T2>
    bool operator==(const polymorphic_allocator<T1>& a,
                    const polymorphic_allocator<T2>& b) noexcept;
  template <class T1, class T2>
    bool operator!=(const polymorphic_allocator<T1>& a,
                    const polymorphic_allocator<T2>& b) noexcept;

  // [mem.res.global], global memory resources
  memory_resource* new_delete_resource() noexcept;
  memory_resource* null_memory_resource() noexcept;
  memory_resource* set_default_resource(memory_resource* r) noexcept;
  memory_resource* get_default_resource() noexcept;

  // [mem.res.pool], pool resource classes
  struct pool_options;
  class synchronized_pool_resource;
  class unsynchronized_pool_resource;
  class monotonic_buffer_resource;
}

23.12.2 Class memory_­resource [mem.res.class]

memory_­resource Класс является абстрактным интерфейсом для неограниченного набора классов , заключающих ресурсы памяти.

class memory_resource {
  static constexpr size_t max_align = alignof(max_align_t); // exposition only

public:
  virtual ~memory_resource();

  void* allocate(size_t bytes, size_t alignment = max_align);
  void deallocate(void* p, size_t bytes, size_t alignment = max_align);

  bool is_equal(const memory_resource& other) const noexcept;

private:
  virtual void* do_allocate(size_t bytes, size_t alignment) = 0;
  virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0;

  virtual bool do_is_equal(const memory_resource& other) const noexcept = 0;
};

23.12.2.1 memory_­resource public member functions [mem.res.public]

~memory_resource();

Effects: Уничтожает это memory_­resource.

void* allocate(size_t bytes, size_t alignment = max_align);

Effects: Эквивалентен: return do_­allocate(bytes, alignment);

void deallocate(void* p, size_t bytes, size_t alignment = max_align);

Effects: Эквивалентен: do_­deallocate(p, bytes, alignment);

bool is_equal(const memory_resource& other) const noexcept;

Effects: Эквивалентен: return do_­is_­equal(other);

23.12.2.2 memory_­resource private virtual member functions [mem.res.private]

virtual void* do_allocate(size_t bytes, size_t alignment) = 0;

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

Returns: Производный класс должен реализовать эту функцию для возврата указателя на выделенный storage ([basic.stc.dynamic.deallocation]) размером не менее bytes. Возвращенное хранилище выравнивается по указанному выравниванию, если такое выравнивание поддерживается ([basic.align]); в противном случае он выравнивается по max_­align.

Throws: Реализация производного класса должна генерировать соответствующее исключение, если не может выделить память с запрошенным размером и выравниванием.

virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0;

Requires: p должен быть возвращен из предыдущего обращения к allocate(bytes, alignment) ресурсу памяти, равному *this, и память в p еще не должна быть освобождена.

Effects: Производный класс должен реализовать эту функцию для удаления выделенной памяти.

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

virtual bool do_is_equal(const memory_resource& other) const noexcept = 0;

Returns: Производный класс должен реализовать эту функцию для возврата, true если память, выделенная из, this может быть освобождена, other и наоборот, в противном случае false. [ Note: Самый производный тип other может не соответствовать типу this. Для производного класса Dтипичная реализация этой функции немедленно вернет false if dynamic_­cast<const D*>(&other) == nullptr. ] end note

23.12.2.3 memory_­resource equality [mem.res.eq]

bool operator==(const memory_resource& a, const memory_resource& b) noexcept;

Returns: &a == &b || a.is_­equal(b).

bool operator!=(const memory_resource& a, const memory_resource& b) noexcept;

Returns: !(a == b).

23.12.3 Class template polymorphic_­allocator [mem.poly.allocator.class]

Специализация шаблона класса pmr​::​polymorphic_­allocator соответствует стандарту Allocator requirements. Созданные с использованием разных ресурсов памяти, разные экземпляры одной и той же специализации pmr​::​polymorphic_­allocator могут демонстрировать совершенно разное поведение распределения. Этот полиморфизм времени выполнения позволяет объектам, которые используют, polymorphic_­allocator вести себя так, как если бы они использовали разные типы распределителей во время выполнения, даже если они используют один и тот же тип статического распределителя.

template <class Tp>
class polymorphic_allocator {
  memory_resource* memory_rsrc; // exposition only

public:
  using value_type = Tp;

  // [mem.poly.allocator.ctor], constructors
  polymorphic_allocator() noexcept;
  polymorphic_allocator(memory_resource* r);

  polymorphic_allocator(const polymorphic_allocator& other) = default;

  template <class U>
    polymorphic_allocator(const polymorphic_allocator<U>& other) noexcept;

  polymorphic_allocator&
    operator=(const polymorphic_allocator& rhs) = delete;

  // [mem.poly.allocator.mem], member functions
  Tp* allocate(size_t n);
  void deallocate(Tp* p, size_t n);

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

  template <class T1, class T2, class... Args1, class... Args2>
    void construct(pair<T1,T2>* p, piecewise_construct_t,
                   tuple<Args1...> x, tuple<Args2...> y);
  template <class T1, class T2>
    void construct(pair<T1,T2>* p);
  template <class T1, class T2, class U, class V>
    void construct(pair<T1,T2>* p, U&& x, V&& y);
  template <class T1, class T2, class U, class V>
    void construct(pair<T1,T2>* p, const pair<U, V>& pr);
  template <class T1, class T2, class U, class V>
    void construct(pair<T1,T2>* p, pair<U, V>&& pr);

  template <class T>
    void destroy(T* p);

  polymorphic_allocator select_on_container_copy_construction() const;

  memory_resource* resource() const;
};

23.12.3.1 polymorphic_­allocator constructors [mem.poly.allocator.ctor]

polymorphic_allocator() noexcept;

Effects: Устанавливается memory_­rsrc на get_­default_­resource().

polymorphic_allocator(memory_resource* r);

Requires: r не равно нулю.

Effects: Устанавливается memory_­rsrc на r.

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

[ Note: Этот конструктор обеспечивает неявное преобразование из memory_­resource*. ] end note

template <class U> polymorphic_allocator(const polymorphic_allocator<U>& other) noexcept;

Effects: Устанавливается memory_­rsrc на other.resource().

23.12.3.2 polymorphic_­allocator member functions [mem.poly.allocator.mem]

Tp* allocate(size_t n);

Returns: Эквивалентно

return static_cast<Tp*>(memory_rsrc->allocate(n * sizeof(Tp), alignof(Tp)));
void deallocate(Tp* p, size_t n);

Requires: p был выделен из ресурса памяти x, равного *memory_­rsrc, с использованием x.allocate(n * sizeof(Tp), alignof(Tp)).

Effects: Эквивалентно memory_­rsrc->deallocate(p, n * sizeof(Tp), alignof(Tp)).

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

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

Requires: Конструкция Uses-allocator T с распределителем resource() (см. [allocator.uses.construction]) И аргументами конструктора std​::​forward<Args>(args)... сформирована правильно. [ Note: Конструкция Uses-allocator всегда хорошо сформирована для типов, которые не используют распределители. ]end note

Effects: Создайте T объект в хранилище, адрес которого представлен конструкцией p uses-allocator с resource() аргументами распределителя и конструктора std​::​forward<Args>(args)....

Throws: Ничего, кроме конструктора для T бросков.

template <class T1, class T2, class... Args1, class... Args2> void construct(pair<T1,T2>* p, piecewise_construct_t, tuple<Args1...> x, tuple<Args2...> y);

[ Note: Этот метод и construct последующие методы являются перегрузками для кусочного построения пар ([pairs.pair]). ]end note

Effects: Позвольте xprime быть tuple построенным из x согласно соответствующему правилу из следующего списка. [ Note: Следующее описание можно резюмировать как создание pair<T1, T2> объекта в хранилище, адрес которого представлен p, как если бы с помощью отдельной конструкции uses-allocator с allocator resource() ([allocator.uses.construction]), p->first использующей элементы x и p->second элементы y. ] end note

  • Если uses_­allocator_­v<T1,memory_­resource*> есть и есть , значит, есть . false
    is_­constructible_­v<T1,Args1...> true
    xprime x

  • В противном случае, если uses_­allocator_­v<T1,memory_­resource*> есть и есть , то есть . true
    is_­constructible_­v<T1,allocator_­arg_­t,memory_­resource*,Args1...> true
    xprime tuple_­cat(make_­tuple(allocator_­arg, resource()), std​::​move(x))

  • В противном случае, если uses_­allocator_­v<T1,memory_­resource*> есть и есть , то есть . true
    is_­constructible_­v<T1,Args1...,memory_­resource*> true
    xprime tuple_­cat(std​::​move(x), make_­tuple(resource()))

  • В противном случае программа плохо сформирована.

Позвольте yprime быть кортежем, построенным y согласно соответствующему правилу из следующего списка:

  • Если uses_­allocator_­v<T2,memory_­resource*> есть и есть , значит, есть . false
    is_­constructible_­v<T2,Args2...> true
    yprime y

  • В противном случае, если uses_­allocator_­v<T2,memory_­resource*> есть и есть , то есть . true
    is_­constructible_­v<T2,allocator_­arg_­t,memory_­resource*,Args2...> true
    yprime tuple_­cat(make_­tuple(allocator_­arg, resource()), std​::​move(y))

  • В противном случае, если uses_­allocator_­v<T2,memory_­resource*> есть и есть , то есть . true
    is_­constructible_­v<T2,Args2...,memory_­resource*> true
    yprime tuple_­cat(std​::​move(y), make_­tuple(resource()))

  • В противном случае программа плохо сформирована.

Затем, используя piecewise_­construct, xprimeи yprime в качестве аргументов конструктора, эта функция создает pair<T1, T2> объект в хранилище, адрес которого представлен как p.

template <class T1, class T2> void construct(pair<T1,T2>* p);

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

construct(p, piecewise_construct, tuple<>(), tuple<>());

template <class T1, class T2, class U, class V> void construct(pair<T1,T2>* p, U&& x, V&& y);

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

construct(p, piecewise_construct,
          forward_as_tuple(std::forward<U>(x)),
          forward_as_tuple(std::forward<V>(y)));

template <class T1, class T2, class U, class V> void construct(pair<T1,T2>* p, const pair<U, V>& pr);

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

construct(p, piecewise_construct,
          forward_as_tuple(pr.first),
          forward_as_tuple(pr.second));

template <class T1, class T2, class U, class V> void construct(pair<T1,T2>* p, pair<U, V>&& pr);

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

construct(p, piecewise_construct,
          forward_as_tuple(std::forward<U>(pr.first)),
          forward_as_tuple(std::forward<V>(pr.second)));

template <class T> void destroy(T* p);

Effects: Как будто мимо p->~T().

polymorphic_allocator select_on_container_copy_construction() const;

Returns: polymorphic_­allocator().

[ Note: Ресурс памяти не распространяется. ] end note

memory_resource* resource() const;

Returns: memory_­rsrc.

23.12.3.3 polymorphic_­allocator equality [mem.poly.allocator.eq]

template <class T1, class T2> bool operator==(const polymorphic_allocator<T1>& a, const polymorphic_allocator<T2>& b) noexcept;

Returns: *a.resource() == *b.resource().

template <class T1, class T2> bool operator!=(const polymorphic_allocator<T1>& a, const polymorphic_allocator<T2>& b) noexcept;

Returns: !(a == b).

23.12.4 Access to program-wide memory_­resource objects [mem.res.global]

memory_resource* new_delete_resource() noexcept;

Returns: Указатель на объект статической продолжительности типа, производного от memory_­resource этого, может служить ресурсом для выделения памяти с помощью ​::​operator new и ​::​operator delete. При каждом вызове этой функции возвращается одно и то же значение. Для возвращаемого значения p и ресурс памяти r, p->is_­equal(r) возвращается &r == p.

memory_resource* null_memory_resource() noexcept;

Returns: Указатель на объект статической продолжительности типа, производного от memory_­resource которого allocate() всегда выбрасывает bad_­alloc и для которого deallocate() не действует. При каждом вызове этой функции возвращается одно и то же значение. Для возвращаемого значения p и ресурс памяти r, p->is_­equal(r) возвращается &r == p.

Это default memory resource pointer указатель на ресурс памяти, который используется некоторыми средствами, когда явный ресурс памяти не предоставляется через интерфейс. Его начальное значение - это возвращаемое значение new_­delete_­resource().

memory_resource* set_default_resource(memory_resource* r) noexcept;

Effects: Если не r равно нулю, устанавливает значение указателя ресурса памяти по умолчанию на r, в противном случае устанавливает указатель ресурса памяти по умолчанию на new_­delete_­resource().

Postconditions: get_­default_­resource() == r.

Returns: Предыдущее значение указателя ресурса памяти по умолчанию.

Remarks: Вызов set_­default_­resource и get_­default_­resource функция не влечет за собой гонку данных. Вызов к set_­default_­resource функции будет синхронизировать с последующими вызовами set_­default_­resource и get_­default_­resource функциями.

memory_resource* get_default_resource() noexcept;

Returns: Текущее значение указателя ресурса памяти по умолчанию.

23.12.5 Pool resource classes [mem.res.pool]

23.12.5.1 Classes synchronized_­pool_­resource and unsynchronized_­pool_­resource [mem.res.pool.overview]

В synchronized_­pool_­resource и unsynchronized_­pool_­resource классах (вместе называемые pool resource classes) являются ресурсами памяти общего назначения , имеющие следующие свойства:

  • Каждый ресурс освобождает свою выделенную память при уничтожении, даже если deallocate не был вызван для некоторых из выделенных блоков.

  • Ресурс пула состоит из набора pools, обслуживающего запросы для блоков разного размера. Каждый отдельный пул управляет коллекцией, chunks которая, в свою очередь, разделена на блоки одинакового размера, которые возвращаются через вызовы do_­allocate. Каждый вызов do_­allocate(size, alignment) отправляется в пул, обслуживающий самые маленькие блоки, вмещающие не менее size байтов.

  • Когда конкретный пул исчерпан, выделение блока из этого пула приводит к выделению дополнительного фрагмента памяти из upstream allocator (предоставленного при построении), таким образом пополняя пул. При каждом последующем пополнении размер получаемого блока увеличивается геометрически. [ Note: Распределяя память по частям, стратегия объединения увеличивает вероятность того, что последовательные распределения будут близки друг к другу в памяти. ] end note

  • Запросы на выделение, превышающие самый большой размер блока любого пула, выполняются непосредственно из вышестоящего распределителя.

  • pool_­options Структура может быть передана в конструкторах пул ресурсов для настройки самого большого размера блока и максимальный размер порции.

synchronized_­pool_­resource Доступ к A может осуществляться из нескольких потоков без внешней синхронизации, и он может иметь пулы, зависящие от потока, для снижения затрат на синхронизацию. К unsynchronized_­pool_­resource классу нельзя получить доступ из нескольких потоков одновременно, что позволяет полностью избежать затрат на синхронизацию в однопоточных приложениях.

struct pool_options {
  size_t max_blocks_per_chunk = 0;
  size_t largest_required_pool_block = 0;
};

class synchronized_pool_resource : public memory_resource {
public:
  synchronized_pool_resource(const pool_options& opts,
                             memory_resource* upstream);

  synchronized_pool_resource()
      : synchronized_pool_resource(pool_options(), get_default_resource()) {}
  explicit synchronized_pool_resource(memory_resource* upstream)
      : synchronized_pool_resource(pool_options(), upstream) {}
  explicit synchronized_pool_resource(const pool_options& opts)
      : synchronized_pool_resource(opts, get_default_resource()) {}

  synchronized_pool_resource(const synchronized_pool_resource&) = delete;
  virtual ~synchronized_pool_resource();

  synchronized_pool_resource&
    operator=(const synchronized_pool_resource&) = delete;

  void release();
  memory_resource* upstream_resource() const;
  pool_options options() const;

protected:
  void *do_allocate(size_t bytes, size_t alignment) override;
  void do_deallocate(void *p, size_t bytes, size_t alignment) override;

  bool do_is_equal(const memory_resource& other) const noexcept override;
};

class unsynchronized_pool_resource : public memory_resource {
public:
  unsynchronized_pool_resource(const pool_options& opts,
                               memory_resource* upstream);

  unsynchronized_pool_resource()
      : unsynchronized_pool_resource(pool_options(), get_default_resource()) {}
  explicit unsynchronized_pool_resource(memory_resource* upstream)
      : unsynchronized_pool_resource(pool_options(), upstream) {}
  explicit unsynchronized_pool_resource(const pool_options& opts)
      : unsynchronized_pool_resource(opts, get_default_resource()) {}

  unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete;
  virtual ~unsynchronized_pool_resource();

  unsynchronized_pool_resource&
    operator=(const unsynchronized_pool_resource&) = delete;

  void release();
  memory_resource *upstream_resource() const;
  pool_options options() const;

protected:
  void* do_allocate(size_t bytes, size_t alignment) override;
  void do_deallocate(void* p, size_t bytes, size_t alignment) override;

  bool do_is_equal(const memory_resource& other) const noexcept override;
};

23.12.5.2 pool_­options data members [mem.res.pool.options]

Члены pool_­options составляют набор параметров конструктора для ресурсов пула. Влияние каждой опции на поведение ресурсов пула описано ниже:

size_t max_blocks_per_chunk;

Максимальное количество блоков, которые будут одновременно выделены из восходящего ресурса памяти ([mem.res.monotonic.buffer]) для пополнения пула. Если значение max_­blocks_­per_­chunk равно нулю или превышает предел, определенный реализацией, вместо него используется этот предел. Реализация может выбрать использование меньшего значения, чем указано в этом поле, и может использовать разные значения для разных пулов.

size_t largest_required_pool_block;

Наибольший размер выделения, который требуется выполнить с помощью механизма объединения. Попытки выделить один блок, размер которого превышает этот порог, будут выделяться непосредственно из ресурса памяти восходящего потока. Если он largest_­required_­pool_­block равен нулю или превышает предел, определенный реализацией, вместо него используется этот предел. Реализация может выбрать порог прохождения больше, чем указано в этом поле.

23.12.5.3 Pool resource constructors and destructors [mem.res.pool.ctor]

synchronized_pool_resource(const pool_options& opts, memory_resource* upstream); unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream);

Requires: upstream это адрес допустимого ресурса памяти.

Effects: Создает объект ресурса пула, который будет получать память upstream всякий раз, когда ресурс пула не может удовлетворить запрос памяти из своих собственных внутренних структур данных. Результирующий объект будет содержать копию upstream, но не будет владеть ресурсом, на который upstream указывает. [ Note: Предполагается, что в большинстве случаев звонков на upstream->allocate() адрес будет значительно меньше, чем на this->allocate()адрес. ] Поведение механизма объединения настраивается в соответствии со значением аргумента.end note opts

Throws: Ничего, разве что upstream->allocate() кидает. Не указано, вызывает ли этот конструктор и при каких условиях upstream->allocate().

virtual ~synchronized_pool_resource(); virtual ~unsynchronized_pool_resource();

Effects: Звонки release().

23.12.5.4 Pool resource members [mem.res.pool.mem]

void release();

Effects: Вызывает по upstream_­resource()->deallocate() мере необходимости для освобождения всей выделенной памяти. [ Note: Память возвращается обратно, upstream_­resource() даже если deallocate не была вызвана для некоторых из выделенных блоков. ] end note

memory_resource* upstream_resource() const;

Returns: Значение upstream аргумента, предоставленное конструктору этого объекта.

pool_options options() const;

Returns: Параметры, управляющие поведением пула этого ресурса. Значения в возвращаемой структуре могут отличаться от тех, которые предоставлены конструктору ресурсов пула, поскольку нулевые значения будут заменены значениями по умолчанию, определяемыми реализацией, а размеры могут быть округлены до неопределенной степени детализации.

void* do_allocate(size_t bytes, size_t alignment) override;

Returns: Указатель на выделенное хранилище ([basic.stc.dynamic.deallocation]) размером не менее bytes. Размер и выравнивание выделенной памяти должны соответствовать требованиям для класса, производного от memory_­resource.

Effects: Если пул, выбранный для блока размера bytes , не может удовлетворить запрос памяти из своих собственных внутренних структур данных, он вызовет upstream_­resource()->allocate() для получения дополнительной памяти. Если bytes он больше, чем тот, который может обработать самый большой пул, то память будет выделена с использованием upstream_­resource()->allocate().

Throws: Ничего, разве что upstream_­resource()->allocate() кидает.

void do_deallocate(void* p, size_t bytes, size_t alignment) override;

Effects: Возвращает память в p пул. Не указано, приведет ли эта операция к вызову или при каких обстоятельствах upstream_­resource()->deallocate().

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

bool synchronized_pool_resource::do_is_equal( const memory_resource& other) const noexcept override;

Returns: this == dynamic_­cast<const synchronized_­pool_­resource*>(&other).

bool unsynchronized_pool_resource::do_is_equal( const memory_resource& other) const noexcept override;

Returns: this == dynamic_­cast<const unsynchronized_­pool_­resource*>(&other).

23.12.6 Class monotonic_­buffer_­resource [mem.res.monotonic.buffer]

A monotonic_­buffer_­resource - это ресурс памяти специального назначения, предназначенный для очень быстрого выделения памяти в ситуациях, когда память используется для создания нескольких объектов, а затем освобождается сразу после уничтожения объекта ресурса памяти. Обладает следующими качествами:

  • Обращение к не deallocate имеет никакого эффекта, поэтому объем потребляемой памяти монотонно увеличивается до тех пор, пока ресурс не будет уничтожен.

  • Программа может предоставить начальный буфер, который распределитель использует для удовлетворения запросов памяти.

  • Когда исходный буфер (если он есть) исчерпан, он получает дополнительные буферы из upstream ресурса памяти, предоставленного при построении. Каждый дополнительный буфер больше предыдущего в геометрической прогрессии.

  • Он предназначен для доступа из одного потока управления за раз. В частности, вызовы allocate и deallocate не синхронизируются друг с другом.

  • Он освобождает выделенную память при уничтожении, даже если deallocate не был вызван для некоторых из выделенных блоков.

class monotonic_buffer_resource : public memory_resource {
  memory_resource *upstream_rsrc; // exposition only
  void *current_buffer;           // exposition only
  size_t next_buffer_size;        // exposition only

public:
  explicit monotonic_buffer_resource(memory_resource *upstream);
  monotonic_buffer_resource(size_t initial_size, memory_resource *upstream);
  monotonic_buffer_resource(void *buffer, size_t buffer_size,
                            memory_resource *upstream);

  monotonic_buffer_resource()
      : monotonic_buffer_resource(get_default_resource()) {}
  explicit monotonic_buffer_resource(size_t initial_size)
      : monotonic_buffer_resource(initial_size, get_default_resource()) {}
  monotonic_buffer_resource(void *buffer, size_t buffer_size)
      : monotonic_buffer_resource(buffer, buffer_size, get_default_resource()) {}

  monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;

  virtual ~monotonic_buffer_resource();

  monotonic_buffer_resource
    operator=(const monotonic_buffer_resource&) = delete;

  void release();
  memory_resource* upstream_resource() const;

protected:
  void* do_allocate(size_t bytes, size_t alignment) override;
  void do_deallocate(void* p, size_t bytes, size_t alignment) override;

  bool do_is_equal(const memory_resource& other) const noexcept override;
};

23.12.6.1 monotonic_­buffer_­resource constructor and destructor [mem.res.monotonic.buffer.ctor]

explicit monotonic_buffer_resource(memory_resource* upstream); monotonic_buffer_resource(size_t initial_size, memory_resource* upstream);

Requires: upstream должен быть адресом допустимого ресурса памяти. initial_­size, если указано, должно быть больше нуля.

Effects: Устанавливает upstream_­rsrc на upstream и current_­buffer на nullptr. Если initial_­size указано, устанавливается next_­buffer_­size как минимум initial_­size; в противном случае устанавливает next_­buffer_­size к реализации определенных размеров.

monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream);

Requires: upstream должен быть адресом допустимого ресурса памяти. buffer_­size не должно быть больше, чем количество байтов в buffer.

Effects: Устанавливается upstream_­rsrc в upstream, current_­buffer в bufferи next_­buffer_­size в buffer_­size (но не менее 1), затем увеличивается next_­buffer_­size на коэффициент роста, определяемый реализацией (который не обязательно должен быть целым).

~monotonic_buffer_resource();

Effects: Звонки release().

23.12.6.2 monotonic_­buffer_­resource members [mem.res.monotonic.buffer.mem]

void release();

Effects: Вызывает по upstream_­rsrc->deallocate() мере необходимости для освобождения всей выделенной памяти.

[ Note: Память возвращается обратно, upstream_­rsrc даже если некоторые блоки, которые были выделены из this , не были освобождены this. ] end note

memory_resource* upstream_resource() const;

Returns: Ценность upstream_­rsrc.

void* do_allocate(size_t bytes, size_t alignment) override;

Returns: Указатель на выделенное хранилище ([basic.stc.dynamic.deallocation]) размером не менее bytes. Размер и выравнивание выделенной памяти должны соответствовать требованиям для класса, производного от memory_­resource.

Effects: Если неиспользуемое пространство в current_­buffer может уместиться в блоке с указанными bytes и alignment, то выделите возвращаемый блок из current_­buffer; в противном случае устанавливается current_­buffer значение upstream_­rsrc->allocate(n, m), где n не меньше max(bytes, next_­buffer_­size) и m не меньше alignment, и увеличивается next_­buffer_­size на коэффициент роста, определяемый реализацией (который не обязательно должен быть целым), затем выделять блок возврата из вновь выделенного current_­buffer.

Throws: Ничего, разве что upstream_­rsrc->allocate() кидает.

void do_deallocate(void* p, size_t bytes, size_t alignment) override;

Effects: Никто.

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

Remarks: Память, используемая этим ресурсом, монотонно увеличивается до тех пор, пока не будет уничтожена.

bool do_is_equal(const memory_resource& other) const noexcept override;

Returns: this == dynamic_­cast<const monotonic_­buffer_­resource*>(&other).