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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With