name keywords etiquetas ejemplos description c++ allocator c++17

c++ - keywords - meta tags ejemplos



polymorphic_allocator: ¿cuándo y por qué debería usarlo? (3)

Cita de elección de cppreference:

Este polimorfismo de tiempo de ejecución permite que los objetos que utilizan el asignador polimórfico se comporten como si usaran diferentes tipos de asignadores en tiempo de ejecución a pesar del tipo de asignador estático idéntico

El problema con los asignadores "regulares" es que cambian el tipo de contenedor. Si desea un vector con un asignador específico, puede utilizar el parámetro de plantilla Allocator :

auto my_vector = std::vector<int,my_allocator>();

El problema ahora es que este vector no es del mismo tipo que un vector con un asignador diferente. No puede pasarlo a una función que requiera un vector de asignación predeterminado, por ejemplo, o asignar dos vectores con un tipo de asignación diferente a la misma variable / puntero, por ejemplo:

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

Un asignador polimórfico es un tipo de asignador único con un miembro que puede definir el comportamiento del asignador a través del envío dinámico en lugar de a través del mecanismo de plantilla. Esto le permite tener contenedores que usan una asignación específica y personalizada, pero que todavía son de un tipo común.

La personalización del comportamiento del asignador se realiza dando al asignador un 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

El principal problema que queda, según lo veo, es que un std::pmr:: container todavía no es compatible con el std:: container equivalente usando el asignador predeterminado. Debe tomar algunas decisiones al momento de diseñar una interfaz que funcione con un contenedor:

  • ¿Es probable que el contenedor pasado pueda requerir una asignación personalizada?
  • Si es así, ¿debo agregar un parámetro de plantilla (para permitir asignadores arbitrarios) o debo ordenar el uso de un asignador polimórfico?

Una solución de plantilla permite cualquier asignador, incluido un asignador polimórfico, pero tiene otros inconvenientes (el tamaño del código generado, el tiempo de compilación, el código debe exponerse en el archivo de encabezado, la posibilidad de una mayor "contaminación tipo" que sigue empujando el problema hacia afuera). Una solución de asignador polimórfico, por otro lado, dicta que se debe utilizar un asignador polimórfico. Esto impide el uso de contenedores std:: que usan el asignador predeterminado y pueden tener implicaciones para interactuar con el código heredado.

En comparación con un asignador regular, un asignador polimórfico tiene algunos costos menores, como la sobrecarga de almacenamiento del puntero memory_resource (que probablemente sea insignificante) y el costo del envío de funciones virtuales para las asignaciones. El problema principal, en realidad, es probablemente la falta de compatibilidad con el código heredado que no utiliza asignadores polimórficos.

Here está la documentación sobre cppreference , here está el borrador de trabajo.

Debo admitir que no entendí cuál es el verdadero propósito de polymorphic_allocator y cuándo / por qué / cómo debería usarlo.
Como ejemplo, el pmr::vector tiene la siguiente firma:

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

¿Qué ofrece el polymorphic_allocator ? ¿Qué ofrece también el std::pmr::vector en relación con el antiguo std::vector ? ¿Qué puedo hacer ahora que no podía hacer hasta ahora?
¿Cuál es el verdadero propósito de ese asignador y cuándo debo usarlo realmente?


Un inconveniente de los asignadores polimórficos es que el polymorphic_allocator<T>::pointer siempre es solo T* . Eso significa que no puedes usarlos con punteros elegantes . Si desea hacer algo como colocar elementos de un vector en la memoria compartida y acceder a ellos a través de boost::interprocess::offset_ptr s , debe usar un antiguo asignador no polimórfico antiguo para eso.

Entonces, aunque los asignadores polimórficos le permiten variar el comportamiento de la asignación sin cambiar el tipo estático de un contenedor, limitan lo que es una asignación .


polymorphic_allocator es para un asignador personalizado como std::function es para una llamada de función directa.

Simplemente le permite usar un asignador con su contenedor sin tener que decidir, en el momento de la declaración, cuál. Entonces, si tiene una situación en la que más de un asignador sería apropiado, puede usar polymorphic_allocator .

Tal vez desee ocultar qué asignador se utiliza para simplificar su interfaz, o tal vez quiera cambiarlo por diferentes casos de tiempo de ejecución.

Primero necesita un código que necesita un asignador, luego necesita poder intercambiar cuál se usa, antes de considerar el vector pmr.