Citação de escolha de cppreference:
Este polimorfismo de tempo de execução permite que os objetos que usam polymorphic_allocator se comportem como se usassem diferentes tipos de alocadores em tempo de execução, apesar do tipo de alocador estático idêntico
O problema com os alocadores "regulares" é que eles mudam o tipo do contêiner. Se você quiser um vector
com um alocador específico, pode usar o Allocator
parâmetro do modelo:
auto my_vector = std::vector<int,my_allocator>();
O problema agora é que esse vetor não é do mesmo tipo que um vetor com um alocador diferente. Você não pode passá-lo para uma função que requer um vetor alocador padrão, por exemplo, ou atribuir dois vetores com um tipo de alocador diferente para a mesma variável / ponteiro, por exemplo:
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
Um alocador polimórfico é um único tipo de alocador com um membro que pode definir o comportamento do alocador por meio de despacho dinâmico em vez de por meio do mecanismo de modelo. Isso permite que você tenha contêineres que usam alocação específica e personalizada, mas que ainda são de um tipo comum.
A personalização do comportamento do alocador é feita dando ao alocador um 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
O principal problema remanescente, a meu ver, é que um std::pmr::
contêiner ainda não é compatível com o std::
contêiner equivalente que usa o alocador padrão. Você precisa tomar algumas decisões no momento de projetar uma interface que funcione com um contêiner:
- é provável que o contêiner passado possa exigir alocação personalizada?
- em caso afirmativo, devo adicionar um parâmetro de modelo (para permitir alocadores arbitrários) ou devo obrigar o uso de um alocador polimórfico?
Uma solução de modelo permite qualquer alocador, incluindo um alocador polimórfico, mas tem outras desvantagens (tamanho do código gerado, tempo de compilação, o código deve ser exposto no arquivo de cabeçalho, potencial para mais "contaminação de tipo" que continua empurrando o problema para fora). Uma solução de alocador polimórfico, por outro lado, determina que um alocador polimórfico deve ser usado. Isso impede o uso de std::
contêineres que usam o alocador padrão e pode ter implicações para a interface com o código legado.
Comparado a um alocador regular, um alocador polimórfico tem alguns custos menores, como a sobrecarga de armazenamento do ponteiro memory_resource (que é provavelmente insignificante) e o custo de despacho de função virtual para alocações. O principal problema, realmente, é provavelmente a falta de compatibilidade com o código legado que não usa alocadores polimórficos.
allocator<T>
inerentemente. Portanto, você verá valor nisso se usar alocadores com frequência.