Question

I was trying to use a custom allocator for std::vector<char>, but I noticed that std::vector does not need/use any of the member functions from my allocator. How is this possible?

#include <vector>

struct A : private std::allocator<char> {
   typedef std::allocator<char> alloc;
   using alloc::value_type;
   using alloc::pointer;
   using alloc::const_pointer;
   using alloc::difference_type;
   using alloc::size_type;
   using alloc::rebind;
   // member functions have been removed, since the program compiles without them
};

int main() {
    std::vector<char, A> v;
    v.resize(4000);
    for (auto& c : v)
      if (c)
         return 1; // never happens in my environment
   return 0; // all elements initialized to 0. How is this possible?
}

I was trying the above program with an online C++11 compiler (LiveWorkSpace), providing g++ 4.7.2, 4.8 and 4.6.3.

Basically allocate(), deallocate(), construct() and destroy() are not defined in my allocator, yet the program compiles and all the elements will be initialized to 0.

Was it helpful?

Solution

The GCC standard library will always rebind the supplied allocator so internally it does something like this (in C++03):

typedef Alloc::template rebind<value_type>::other _Allocator_type;

(In C++11 it uses allocator_traits but in this case the result is the same.)

The vector then stores an object of that type internally and uses it for all (de)allocation.

Since you haven't defined a rebind member template in your allocator, you've just redeclared the one from the base class, the result of the rebinding is std::allocator<value_type> and not your own type. std::allocator of course provides all those functions, so those are the ones that are used, whether or not you define them on your own type.

You can fix it by adding this to your allocator intead of using alloc::rebind; so that vector stores and uses an A internally:

struct A : private std::allocator<char> {
    template<typename U>
      struct rebind {
        typedef A other;
      };

N.B. this will only work for vector, because vector doesn't strictly need to rebind the allocator (users are required to instantiate the template with allocator<value_type>, but GCC's vector rebinds anyway so that if users instantiate vector<int, std::allocator<char>> it still works.) For node-based containers such as std::set your allocator must be a template that can be rebound, because the container needs to allocate its internal node types, not the value_type, so it needs Alloc::rebind<internal_node_type>::other to be valid.

OTHER TIPS

vector will rebind the allocator. As you bring it into scope from std::allocator, A::rebind<T>::other will simply be std::allocator<T>. So everything works fine.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top