Выборочная цитата из cppreference:
Этот полиморфизм времени выполнения позволяет объектам, использующим polymorphic_allocator, вести себя так, как если бы они использовали разные типы распределителей во время выполнения, несмотря на идентичный тип статического распределителя.
Проблема с «обычными» распределителями в том, что они меняют тип контейнера. Если вам нужен vector
конкретный распределитель, вы можете использовать Allocator
параметр шаблона:
auto my_vector = std::vector<int,my_allocator>();
Проблема в том, что этот вектор не того же типа, что и вектор с другим распределителем. Вы не можете передать его функции, которая требует, например, вектора распределителя по умолчанию, или назначить два вектора с другим типом распределителя одной и той же переменной / указателю, например:
auto my_vector = std::vector<int,my_allocator>();
auto my_vector2 = std::vector<int,other_allocator>();
auto vec = my_vector; // ok
vec = my_vector2; // error
Полиморфный распределитель - это отдельный тип распределителя с членом, который может определять поведение распределителя через динамическую отправку, а не через механизм шаблона. Это позволяет вам иметь контейнеры, которые используют конкретное настраиваемое распределение, но все же имеют общий тип.
Настройка поведения распределителя выполняется путем предоставления распределителю std::memory_resource *
:
// define allocation behaviour via a custom "memory_resource"
class my_memory_resource : public std::pmr::memory_resource { ... };
my_memory_resource mem_res;
auto my_vector = std::pmr::vector<int>(0, &mem_res);
// define a second memory resource
class other_memory_resource : public std::pmr::memory_resource { ... };
other_memory_resource mem_res_other;
auto my_other_vector = std::pmr::vector<int>(0, &mes_res_other);
auto vec = my_vector; // type is std::pmr::vector<int>
vec = my_other_vector; // this is ok -
// my_vector and my_other_vector have same type
На мой взгляд, основная оставшаяся проблема заключается в том, что std::pmr::
контейнер все еще несовместим с эквивалентным std::
контейнером, использующим распределитель по умолчанию. При разработке интерфейса, работающего с контейнером, вам нужно принять некоторые решения:
- Возможно ли, что переданный контейнер потребует особого распределения?
- если да, следует ли мне добавить параметр шаблона (чтобы разрешить использование произвольных распределителей) или мне следует обязать использование полиморфного распределителя?
Шаблонное решение позволяет использовать любой распределитель, включая полиморфный распределитель, но имеет другие недостатки (размер сгенерированного кода, время компиляции, код должен быть представлен в файле заголовка, возможность дальнейшего «загрязнения типов», которое продолжает выталкивать проблему наружу). Полиморфный раствор Распределитель с другой стороны , диктует , что полиморфная Распределитель должны быть использованы. Это исключает использование std::
контейнеров, которые используют распределитель по умолчанию, и может иметь последствия для взаимодействия с устаревшим кодом.
По сравнению с обычным распределителем, полиморфный распределитель имеет некоторые незначительные затраты, такие как накладные расходы на хранилище указателя memory_resource (что, скорее всего, незначительно) и стоимость диспетчеризации виртуальных функций для распределений. Основная проблема, вероятно, заключается в отсутствии совместимости с устаревшим кодом, который не использует полиморфные распределители памяти.
allocator<T>
своей сути. Таким образом, вы увидите в этом ценность, если будете часто использовать распределители.