Подтвердить что ты не робот

Polymorphic_allocator: когда и зачем использовать его?

Здесь находится документация по cppreference, здесь - рабочий проект.

Я должен признать, что я не понял, какова настоящая цель polymorphic_allocator и когда/почему/как я должен ее использовать.
В качестве примера pmr::vector имеет следующую подпись:

namespace pmr {
    template <class T>
    using vector = std::vector<T, polymorphic_allocator<T>>;
}

Что предлагает polymorphic_allocator? Что предлагает std::pmr::vector в отношении старомодного std::vector? Что я могу сделать сейчас, что я не мог сделать до сих пор?
Какова реальная цель этого распределителя и когда я должен использовать его на самом деле?

4b9b3361

Ответ 1

Цитата выбора из 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

Полиморфный распределитель представляет собой один тип распределителя с элементом, который может определять поведение распределителя посредством динамической диспетчеризации, а не через механизм шаблона. Это позволяет использовать контейнеры, которые используют специфическое, настроенное распределение, но которые по-прежнему имеют общий тип.

Настройка поведения распределителя выполняется путем предоставления распределителю a 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 (что, скорее всего, незначительно) и стоимость отправки виртуальных функций для распределений. На самом деле основная проблема - отсутствие совместимости с устаревшим кодом, который не использует полиморфные распределители.

Ответ 2

polymorphic_allocator относится к настраиваемому распределителю, поскольку std::function относится к вызову прямой функции.

Он просто позволяет вам использовать распределитель с вашим контейнером, не принимая решения в точке объявления, какой из них. Поэтому, если у вас есть ситуация, когда вам понадобится более одного распределителя, вы можете использовать polymorphic_allocator.

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

Сначала вам нужен код, которому нужен распределитель, тогда вам нужно захотеть поменять его, прежде чем рассматривать pmr vector.