11

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.

0

2 Answers 2

14

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.

Sign up to request clarification or add additional context in comments.

13 Comments

Actually, why is it desirable that it still works if the user provides an std::allocator<char> as the allocator for a vector<int>? Doesn't it make more sense to get a compiler error?
I'm not sure it is desirable personally, but it's always been that way. For other containers it makes more sense: if a user says std::map<int, int, std::less<int>, std::allocator<std::pair<int, int>>> it is a convenience to accept it even though technically the allocator is required to be std::allocator<std::pair<const int, int>>
@AndyProwl - allocators really should be template template parameters, but template template parameters didn't exist at the time that the STL (NOTE: STL, not Standard Library) was designed, so rebind was created.
The internal fields are not allocated, they're just members of the object so exist wherever in memory the object exists. Nested containers are no different to any other element type: the object itself and its members will be placed in the memory allocated by the container, if it allocates its own memory (as a nested container will) then that memory will be elsewhere in the address space. See std::scoped_allocator_adaptor for a utility that causes elements to inherit the allocator form their container
please start your own question instead of hijacking the comments of this one
|
7

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.