[mem.res.pool]

# 20 Memory management library [[mem]](./#mem)

## 20.5 Memory resources [[mem.res]](mem.res#pool)

### 20.5.5 Pool resource classes [mem.res.pool]

#### [20.5.5.1](#overview) Classes synchronized_pool_resource and unsynchronized_pool_resource [[mem.res.pool.overview]](mem.res.pool.overview)

[1](#overview-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8081)

The synchronized_pool_resource andunsynchronized_pool_resource classes
(collectively called [*pool resource classes*](#def:pool_resource_classes "20.5.5.1 Classes synchronized_­pool_­resource and unsynchronized_­pool_­resource [mem.res.pool.overview]"))
are general-purpose memory resources having the following qualities:

- [(1.1)](#overview-1.1)

  Each resource frees its allocated memory on destruction,
even if deallocate has not been called for some of the allocated blocks[.](#overview-1.1.sentence-1)

- [(1.2)](#overview-1.2)

  A pool resource consists of a collection of [*pools*](#def:pools "20.5.5.1 Classes synchronized_­pool_­resource and unsynchronized_­pool_­resource [mem.res.pool.overview]"),
serving requests for different block sizes[.](#overview-1.2.sentence-1)
  Each individual pool manages a collection of [*chunks*](#def:chunks "20.5.5.1 Classes synchronized_­pool_­resource and unsynchronized_­pool_­resource [mem.res.pool.overview]") that are in turn divided into blocks of uniform size,
returned via calls to do_allocate[.](#overview-1.2.sentence-2)
  Each call to do_allocate(size, alignment) is dispatched
to the pool serving the smallest blocks accommodating at least size bytes[.](#overview-1.2.sentence-3)

- [(1.3)](#overview-1.3)

  When a particular pool is exhausted,
allocating a block from that pool results in the allocation
of an additional chunk of memory from the [*upstream allocator*](#def:upstream_allocator "20.5.5.1 Classes synchronized_­pool_­resource and unsynchronized_­pool_­resource [mem.res.pool.overview]") (supplied at construction), thus replenishing the pool[.](#overview-1.3.sentence-1)
  With each successive replenishment,
the chunk size obtained increases geometrically[.](#overview-1.3.sentence-2)
  [*Note [1](#overview-note-1)*:
  By allocating memory in chunks,
the pooling strategy increases the chance that consecutive allocations
will be close together in memory[.](#overview-1.3.sentence-3)
 â *end note*]

- [(1.4)](#overview-1.4)

  Allocation requests that exceed the largest block size of any pool
are fulfilled directly from the upstream allocator[.](#overview-1.4.sentence-1)

- [(1.5)](#overview-1.5)

  A pool_options struct may be passed to the pool resource constructors
to tune the largest block size and the maximum chunk size[.](#overview-1.5.sentence-1)

[2](#overview-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8118)

A synchronized_pool_resource may be accessed from multiple threads
without external synchronization
and may have thread-specific pools to reduce synchronization costs[.](#overview-2.sentence-1)

An unsynchronized_pool_resource class may not be accessed
from multiple threads simultaneously
and thus avoids the cost of synchronization entirely
in single-threaded applications[.](#overview-2.sentence-2)

[ð](#lib:pool_options)

namespace std::pmr {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; };}

#### [20.5.5.2](#options) pool_options data members [[mem.res.pool.options]](mem.res.pool.options)

[1](#options-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8195)

The members of pool_options comprise a set of constructor options for pool resources[.](#options-1.sentence-1)

The effect of each option on the pool resource behavior is described below:

[ð](#lib:pool_options,max_blocks_per_chunk)

`size_t max_blocks_per_chunk;
`

[2](#options-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8206)

The maximum number of blocks that will be allocated at once
from the upstream memory resource ([[mem.res.monotonic.buffer]](mem.res.monotonic.buffer "20.5.6 Class monotonic_­buffer_­resource"))
to replenish a pool[.](#options-2.sentence-1)

If the value of max_blocks_per_chunk is zero or
is greater than an implementation-defined
limit, that limit is used instead[.](#options-2.sentence-2)

The implementation
may choose to use a smaller value than is specified in this member and
may use different values for different pools[.](#options-2.sentence-3)

[ð](#lib:pool_options,largest_required_pool_block)

`size_t largest_required_pool_block;
`

[3](#options-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8224)

The largest allocation size that is required to be fulfilled
using the pooling mechanism[.](#options-3.sentence-1)

Attempts to allocate a single block larger than this threshold
will be allocated directly from the upstream memory resource[.](#options-3.sentence-2)

If largest_required_pool_block is zero or
is greater than an implementation-defined
limit, that limit is used instead[.](#options-3.sentence-3)

The implementation may choose a pass-through threshold
larger than specified in this member[.](#options-3.sentence-4)

#### [20.5.5.3](#ctor) Constructors and destructors [[mem.res.pool.ctor]](mem.res.pool.ctor)

[ð](#lib:synchronized_pool_resource,constructor)

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

[1](#ctor-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8246)

*Preconditions*: upstream is the address of a valid memory resource[.](#ctor-1.sentence-1)

[2](#ctor-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8250)

*Effects*: Constructs a pool resource object that will obtain memory from upstream whenever the pool resource is unable to satisfy a memory request
from its own internal data structures[.](#ctor-2.sentence-1)

The resulting object will hold a copy of upstream,
but will not own the resource to which upstream points[.](#ctor-2.sentence-2)

[*Note [1](#ctor-note-1)*:

The intention is that calls to upstream->allocate() will be substantially fewer than calls to this->allocate() in most cases[.](#ctor-2.sentence-3)

â *end note*]

The behavior of the pooling mechanism is tuned
according to the value of the opts argument[.](#ctor-2.sentence-4)

[3](#ctor-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8265)

*Throws*: Nothing unless upstream->allocate() throws[.](#ctor-3.sentence-1)

It is unspecified if, or under what conditions,
this constructor calls upstream->allocate()[.](#ctor-3.sentence-2)

[ð](#lib:synchronized_pool_resource,destructor)

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

[4](#ctor-4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8280)

*Effects*: Calls release()[.](#ctor-4.sentence-1)

#### [20.5.5.4](#mem) Members [[mem.res.pool.mem]](mem.res.pool.mem)

[ð](#lib:release,synchronized_pool_resource)

`void release();
`

[1](#mem-1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8294)

*Effects*: Calls upstream_resource()->deallocate() as necessary
to release all allocated memory[.](#mem-1.sentence-1)

[*Note [1](#mem-note-1)*:

The memory is released back to upstream_resource() even if deallocate has not been called
for some of the allocated blocks[.](#mem-1.sentence-2)

â *end note*]

[ð](#lib:upstream_resource,synchronized_pool_resource)

`memory_resource* upstream_resource() const;
`

[2](#mem-2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8312)

*Returns*: The value of the upstream argument
provided to the constructor of this object[.](#mem-2.sentence-1)

[ð](#lib:options,synchronized_pool_resource)

`pool_options options() const;
`

[3](#mem-3)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8325)

*Returns*: The options that control the pooling behavior of this resource[.](#mem-3.sentence-1)

The values in the returned struct may differ
from those supplied to the pool resource constructor in that
values of zero will be replaced with implementation-defined
defaults, and sizes may be rounded to unspecified granularity[.](#mem-3.sentence-2)

[ð](#lib:do_allocate,synchronized_pool_resource)

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

[4](#mem-4)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8341)

*Effects*: If the pool selected for a block of size bytes is unable to satisfy the memory request from its own internal data structures,
it will call upstream_resource()->allocate() to obtain more memory[.](#mem-4.sentence-1)

If bytes is larger than that which the largest pool can handle,
then memory will be allocated using upstream_resource()->allocate()[.](#mem-4.sentence-2)

[5](#mem-5)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8349)

*Returns*: A pointer to allocated storage ([[basic.stc.dynamic.allocation]](basic.stc.dynamic.allocation "6.8.6.5.2 Allocation functions"))
with a size of at least bytes[.](#mem-5.sentence-1)

The size and alignment of the allocated memory shall meet the requirements
for a class derived from memory_resource ([[mem.res.class]](mem.res.class "20.5.2 Class memory_­resource"))[.](#mem-5.sentence-2)

[6](#mem-6)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8356)

*Throws*: Nothing unless upstream_resource()->allocate() throws[.](#mem-6.sentence-1)

[ð](#lib:do_deallocate,synchronized_pool_resource)

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

[7](#mem-7)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8368)

*Effects*: Returns the memory at p to the pool[.](#mem-7.sentence-1)

It is unspecified if, or under what circumstances,
this operation will result in a call to upstream_resource()->deallocate()[.](#mem-7.sentence-2)

[8](#mem-8)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8374)

*Throws*: Nothing[.](#mem-8.sentence-1)

[ð](#lib:do_is_equal,synchronized_pool_resource)

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

[9](#mem-9)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/memory.tex#L8386)

*Returns*: this == &other[.](#mem-9.sentence-1)
