2011-12-19 12 views
7

Diciamo che creo una lista collegata in STL:Gli allocatori personalizzati in AWL allocano solo i dati effettivi?

list<int, my_allocator<int> > data; 

allora posso usare un allocatore più efficiente, diciamo un pool di memoria. Ma la lista non ha bisogno di allocare la memoria interna come i puntatori avanti e indietro per attraversare la lista? Come saranno assegnati? Usando normale new o in qualche modo usando my_allocator?

+0

Si intende l'implementazione della libreria standard STL o C++ fornita con la toolchain scelta? E quale è quello? –

+0

@ TomalakGeret'kal, cosa? (+1 alla domanda) – avakar

+0

@avakar L'STL era originariamente un progetto SGI. Da allora ci sono state diverse implementazioni del STL (come STLport) e gran parte di esso è stato aggiunto alla libreria standard come definito dal comitato, anche se con alcune modifiche. Tutto ciò lascia * "STL" * un po 'ambiguo in modi che potrebbero influenzare questa domanda. – dmckee

risposta

10

Il contenitore rielabora effettivamente l'allocatore per allocare il proprio materiale di conservazione dei libri. (Non che sarebbe importa per un std::list, ma è vero in generale *). Questo è il motivo per cui i requisiti allocatore standard, impongono l'esistenza del modello rebind:

typedef typename Alloc::template rebind<MyInternalStuff>::other internal_allocator; 

Se il vostro allocatore è Alloc = my_allocator<T>, quindi internal_allocator diventa my_allocator<MyInternalStuff> .

Credo che questo fosse uno dei problemi che Electronic Arts aveva con la libreria standard C++, motivo per cui la loro libreria EASTL utilizza una convenzione diversa per gli allocatori che offre un controllo più stretto.

*) Tipicamente, ogni nodo sarà un oggetto monolitico di qualche tipo Node<T>, quindi suppongo std::list<T, Alloc>solo mai utilizza Alloc::rebind<Node<T>>::other come allocatore.

[Mi dispiace per le modifiche multiple; Ho avuto l'output maciullato e non l'ho interpretato correttamente; Ora andavo a stampare ogni contenitore separatamente e aggiustavo l'output di conseguenza. std::list effettivamente richiede solo una allocatore]


Aggiornamento:. Solo per risatine, ho scritto un po 'di decodifica-allocator che stampa il proprio typename su di costruzione. Ecco l'ingresso:

#include <unordered_map> 
#include <set> 
#include <deque> 
#include <list> 
#include <vector> 
#include <map> 

#include <iostream> 

int main() 
{ 
    std::cout << "----- unordered_map<int, double> -----------" << std::endl; 
    std::unordered_map<int, double, std::hash<int>, std::equal_to<int>, funky_allocator<std::pair<const int, double>>> m { {1, 1.2} }; 
    std::cout << "----- set<int> -----------------------------" << std::endl; 
    std::set<int, std::less<int>, funky_allocator<int>> s; 
    std::cout << "----- deque<int> ---------------------------" << std::endl; 
    std::deque<int, funky_allocator<int>> d; 
    std::cout << "----- list<int> ----------------------------" << std::endl; 
    std::list<int, funky_allocator<int>> l; 
    std::cout << "----- vector<int> --------------------------" << std::endl; 
    std::vector<int, funky_allocator<int>> c; 
    std::cout << "----- map<int, bool> -----------------------" << std::endl; 
    std::map<int, bool, std::less<int>, funky_allocator<std::pair<const int, bool>>> n { { 1, true } }; 
} 

E qui l'output:

----- unordered_map<int, double> ----------- 
Default-construct: funky_allocator<std::pair<int const, double> > 
Copy-construct: funky_allocator<std::__detail::_Hash_node<std::pair<int const, double>, false> > 
Copy-construct: funky_allocator<std::__detail::_Hash_node<std::pair<int const, double>, false>*> 

----- set<int> ----------------------------- 
Default-construct: funky_allocator<std::_Rb_tree_node<int> > 

----- deque<int> --------------------------- 
Default-construct: funky_allocator<int> 
Copy-construct: funky_allocator<int*> 

----- list<int> ---------------------------- 
Default-construct: funky_allocator<std::_List_node<int> > 

----- vector<int> -------------------------- 
Default-construct: funky_allocator<int> 

----- map<int, bool> ----------------------- 
Default-construct: funky_allocator<std::_Rb_tree_node<std::pair<int const, bool> > > 

I dettagli variano a seconda di quale viene utilizzato costruttore: contenitori come set e map potrebbe costruire solo l'allocatore "corretta" in qualche invocazione, mentre in un altro possono costruire prima un oggetto dell'allocatore specificato. In entrambi i casi, l'allocatore specificato non viene mai utilizzato affatto per un paio di contenitori e solo viene utilizzata la versione di ritorno.

+0

Grazie per te-sai-cosa;) –

+0

+1, anche se ti manca 'template' prima di' rebind' :) – avakar

+0

@avakar: Hai ragione, l'ho notato! In effetti, ho appena scritto il mio allocatore demangling che stampa il proprio nome di classe durante l'istanziazione per verificare quanti diversi allocatori richiedono alcuni contenitori popolari. –

Problemi correlati