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.
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? –
@ TomalakGeret'kal, co? (+1 do pytania) – avakar
@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