2016-06-24 9 views
37

Here è la documentazione su cppreference, here è la bozza di lavoro.polimorfico_allocatore: quando e perché dovrei usarlo?

Devo ammettere che non ho capito quale sia il vero scopo di polymorphic_allocator e quando/perché/come dovrei usarlo.
A titolo di esempio, il pmr::vector ha la seguente firma:

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

Cosa offre polymorphic_allocator? Che cosa offre anche l'std::pmr::vector per quanto riguarda il vecchio stile std::vector? Cosa posso fare ora che non ero in grado di fare fino ad ora?
Qual è il vero scopo di questo allocatore e quando dovrei usarlo effettivamente?

+0

Provano a superare alcuni problemi 'allocatore ' intrinsecamente. Quindi vedrai il valore in esso se usi frequentemente gli allocatori. – edmz

+2

Relevant [paper] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3525.pdf). – edmz

+0

@black Davvero interessante, grazie. Ne varrebbe la pena aggiungere una risposta con questa roba? – skypjack

risposta

32

Scelta citazione da cppreference:

Questo runtime polimorfismo permette agli oggetti che utilizzano polymorphic_allocator a comportarsi come se fossero utilizzati diversi tipi allocatore in fase di esecuzione, nonostante l'identica statica tipo allocatore

Il problema con " regolari "allocatori è che cambiano il tipo del contenitore. Se si desidera un vector con un allocatore specifico, è possibile utilizzare il parametro di Allocator modello:

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

Il problema ora è che questo vettore non è dello stesso tipo di un vettore con un allocatore diverso. Non è possibile passare ad una funzione che richiede un vettore default-allocatore, per esempio, o assegnare due vettori con un diverso tipo allocatore alla stessa/puntatore variabile, ad esempio:

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 allocatore polimorfico è un tipo di allocatore singolo con un membro che può definire il comportamento di allocatore tramite dispatch dinamico anziché tramite il meccanismo di modello. Ciò consente di disporre di contenitori che utilizzano allocazioni specifiche e personalizzate, ma che sono ancora di un tipo comune.

La personalizzazione del comportamento allocatore è fatto dando l'allocatore 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 

La principale questione in sospeso, come la vedo io, è che un contenitore std::pmr:: non è ancora compatibile con l'equivalente std:: container usando l'allocatore predefinito.Hai bisogno di fare alcune decisioni al momento di progettare un'interfaccia che funziona con un contenitore:

  • è probabile che il contenitore in passato può richiedere l'assegnazione personalizzato?
  • in tal caso, dovrei aggiungere un parametro modello (per consentire allocatori arbitrari) o dovrei richiedere l'uso di un allocatore polimorfico?

Una soluzione di modello permette qualsiasi allocatore, compreso un allocatore polimorfico, ma presenta altri inconvenienti (dimensioni codice generato, tempo di compilazione, codice deve essere esposta nel file di intestazione, potenziale di ulteriore "tipo contaminazione" che mantiene spingendo il problema verso l'esterno). D'altra parte, una soluzione di allocazione polimorfica stabilisce che un allocatore polimorfico deve essere utilizzato. Ciò preclude l'utilizzo dei contenitori std:: che utilizzano l'allocatore predefinito e potrebbero avere implicazioni per l'interfaccia con il codice legacy.

Rispetto a un allocatore regolare, un allocatore polimorfico presenta alcuni costi minori, come il sovraccarico di memoria del puntatore memory_resource (che è probabilmente trascurabile) e il costo della distribuzione di funzioni virtuali per le allocazioni. Il problema principale, in realtà, è probabilmente la mancanza di compatibilità con il codice legacy che non utilizza allocatori polimorfici.

+0

Quindi, il layout binario delle classi 'std :: pmr ::' molto probabilmente sarà diverso? –

+2

@EuriPinhollow non puoi 'reinterpret_cast' tra un' std :: vector 'e' std :: pmr :: vector ', se è quello che stai chiedendo. – davmac

+0

Fondamentalmente: sì. –

17

polymorphic_allocator è su un allocatore personalizzato come std::function è su una chiamata di funzione diretta.

Semplicemente consente di utilizzare un allocatore con il proprio contenitore senza dover decidere, al momento della dichiarazione, quale. Quindi, se hai una situazione in cui più di un allocatore sarebbe appropriato, puoi usare polymorphic_allocator.

Forse si desidera nascondere quale allocatore viene utilizzato per semplificare l'interfaccia o se si desidera poterlo sostituire per diversi casi di runtime.

Per prima cosa è necessario il codice che richiede un allocatore, quindi è necessario voler essere in grado di scambiare quale viene utilizzato, prima di considerare il vettore pmr.