23 General utilities library [utilities]

23.12 Memory resources [mem.res]

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 noteopts

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).