2011-12-19 8 views
7

Powiedzmy tworzę połączonej listy w STL:Czy niestandardowe alokatory w STL alokują tylko rzeczywiste dane?

list<int, my_allocator<int> > data; 

Następnie można użyć bardziej efektywnego przydzielania, powiedzmy pulę pamięci. Ale czy lista nie musi przydzielać pamięci wewnętrznej, takiej jak wskaźniki do przodu i do tyłu, do przechodzenia przez tę listę? W jaki sposób zostaną one przydzielone? Używając normalnego new lub w jakiś sposób używając my_allocator?

+0

Masz na myśli implementację biblioteki standardowej STL lub C++, która jest dostarczana z wybranym łańcuchem narzędzi? A który to jest? –

+0

@ TomalakGeret'kal, co? (+1 do pytania) – avakar

+0

@avakar STL był pierwotnie projektem sgi. Od tego czasu wdrożono kilka implementacji STL (takich jak STLport), a znaczna część została dodana do standardowej biblioteki określonej przez komisję, aczkolwiek przy kilku zmianach. Wszystko to pozostawia * "STL" * trochę niejednoznaczne w sposób, który może wpłynąć na to pytanie. – dmckee

Odpowiedz

10

Kontener rzeczywiście zmienia przeznaczenie alokatora na alokację własnego materiału księgowego. (Nie, że to ważne dla std::list, ale to prawda w ogóle. *) To dlatego standardowe wymagania podzielnika mandat istnienie rebind Szablon:

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

Jeśli podzielnik jest Alloc = my_allocator<T>, następnie internal_allocator staje my_allocator<MyInternalStuff> .

Wierzę, że było to jednym z błędów, jakie Electronic Arts posiadało w standardowej bibliotece C++, dlatego ich biblioteka EASTL używa innej konwencji dla alokatorów, które oferują ściślejszą kontrolę.

*) Zazwyczaj, każdy węzeł będzie jeden monolityczny przedmiotem pewnego rodzaju Node<T>, więc przypuszczać std::list<T, Alloc>tylko zawsze wykorzystuje Alloc::rebind<Node<T>>::other jako podzielnika.

[Przepraszamy za wiele zmian; Miałem dane wyjściowe i nie interpretowałem ich poprawnie; Teraz poszedłem i wydrukowałem każdy pojemnik osobno i odpowiednio poprawiłem wynik. std::list rzeczywiście wymagają jedynie jeden przydzielania]


Aktualizacja:. Tylko dla chichotów, pisałem trochę demangling-przydzielania który drukuje swój własny TypeName podczas konstrukcji. Oto wejście:

#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 } }; 
} 

I tu wyjście:

----- 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> > > 

Dane różnią się w zależności od których stosowane konstruktor: Kontenery jak set i map może zbudować tylko „prawidłowy” przydzielania w jakimś wezwaniem, podczas gdy w innym mogą najpierw zbudować obiekt określonego alokatora. Tak czy inaczej, określony alokator nigdy nie zostanie w ogóle wykorzystany dla kilku kontenerów, a wersja z odbiciem jest używana.

+0

Dziękuję za Twój know-how;) –

+0

+1, chociaż brakuje ci 'szablonu' przed' rebind' :) – avakar

+0

@avakar: Masz rację, właśnie to zauważyłem! W rzeczywistości, właśnie napisałem własny demangling, który wypisuje własną nazwę klasy podczas tworzenia instancji, aby sprawdzić, ile różnych alokatorów potrzebuje kilka popularnych kontenerów. –

Powiązane problemy