4

std::map definition is copied below:

template<
    class Key,
    class T,
    class Compare = std::less<Key>,
    class Allocator = std::allocator<std::pair<const Key, T> >
> class map;

Based on std::map definition, we can provider customized allocator for its Key and Value.

Questions:

  1. In most situations, std::map is implemented by RB tree. How can we provide customized allocator for RB tree node? I am afraid that we can not do it.
  2. If the answer to the first question is that we can NOT provide customized allocator for RB tree node, we can NOT provide customized allocator for other node-based containers (for example, std::list and std::set), either. Please confirm if my understanding is correct.
JeJo
  • 30,635
  • 6
  • 49
  • 88
Zhongkun Ma
  • 421
  • 2
  • 9
  • 1
    I am not sure if I understand your question correctly, but if you provide a custom allocator, all nodes will be allocated using the provided allocator. – wychmaster Oct 17 '19 at 21:38
  • Thanks for your help. I need to know the node size to calculate the memory pool size. They are using the same allocator, but it allocates memory size of _Rb_tree_node instead of std::pair. – Zhongkun Ma Oct 24 '19 at 07:13
  • The size of a map node depends on the STL implementation. If I remember correctly, on my system it was the size of the pair plus 3 * `sizeof(std::size_t)` which comes from node the pointers. Maybe the following link helps: https://stackoverflow.com/questions/22951378/how-do-you-determine-the-size-of-the-nodes-created-by-a-stdmap-for-use-with – wychmaster Oct 24 '19 at 07:55
  • thanks, it is much safer to use _Rb_tree_node instead of the size of the pair plus 3 * sizeof(std::size_t) – Zhongkun Ma Oct 25 '19 at 13:36

1 Answers1

4

IIRC, the allocator type that you provide as a map template argument is used also for allocation of nodes (namely its allocate member function). You can observe this, for example, in the source code of libstdc++:

typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
   rebind<value_type>::other _Pair_alloc_type;

typedef _Rb_tree<key_type, value_type, _Select1st<value_type>,
    key_compare, _Pair_alloc_type> _Rep_type;

The original allocator parameter _Alloc of std::map is rebound to a map's value type and passed as a template argument to _Rb_tree. There, the allocator is again rebound to the node type _Rb_tree_node<_Val>:

typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
   rebind<_Rb_tree_node<_Val> >::other _Node_allocator;

A typical usage of this mechanism is to exploit some memory pool-based allocator, which might considerably speed-up node allocations. However, beware that this technique is, generally, not straightforward. For instance, with std::unordered_map, the (rebound) allocator type is used both for allocation of nodes and allocation of the array of buckets. In the allocate member function, one then needs to distinguish both allocation types and use memory pooling just for allocation of nodes.

With std::map, there is no array of buckets, so, theoretically, the allocator should be used only for allocation of nodes. However, I am not sure whether this is guaranteed by the Standard.

Daniel Langr
  • 22,196
  • 3
  • 50
  • 93
  • Thanks for your help, I had tried it, it works, I need to know the size of the std::map node to pre-calculate the poll memory size. – Zhongkun Ma Oct 24 '19 at 07:08