The container really reassigns your dispenser to distribute your own accounting material. (Not that it would matter for std::list
, but in reality it is true. *) This is why the requirements of a standard distributor require the existence of a rebind
pattern:
typedef typename Alloc::template rebind<MyInternalStuff>::other internal_allocator;
If your allocator is Alloc = my_allocator<T>
, then internal_allocator
becomes my_allocator<MyInternalStuff>
.
I believe this was one of the problems Electronic Arts had with the C ++ standard library, so their EASTL library uses different convention for distributors, which offers tighter control.
*) Usually each node will be one monolithic object of some type Node<T>
, so I assume that std::list<T, Alloc>
uses Alloc::rebind<Node<T>>::other
only as a distributor.
[Sorry for a few changes; I had a failure, and he did not interpret it correctly; Now I went and printed each container separately and accordingly corrected the output. std::list
really only needs one allocator.]
Update: Just for a giggle, I wrote a small block distributor that prints its own name when building. Here's the input:
#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 } }; }
And here is the conclusion:
----- 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> > >
Details depend on which constructor is used: Containers of type set
and map
can only create the βcorrectβ dispenser in some call, and in another they can first create an object of the specified dispenser. In any case, the specified dispenser will never be used at all for several containers, and only the version of the rebound is used.