I am trying to implement an STL-style container class, and I have a question with respect to the use of allocators within my class:
What is the purpose of the static member functions in STL's allocator_traits
?
Until now, I thought that I am supposed to instantiate the allocator_type
(probably via some kind of empty base optimization to improve the memory footprint). Thus, I would end up with something like this:
struct EmptyBaseOpt : allocator_type
{
EmptyBaseOpt(const allocator_type & a, allocator_type::const_pointer p)
: allocator_type(a), prefix_ptr(p) { }
allocator_type::pointer prefix_ptr;
}
EmptyBaseOpt ebo;
And then, I could use the allocator in the following way:
allocator_type & alloc = ebo;
alloc.allocate(100, ebo.prefix_ptr);
On the other hand, the allocator_traits
in C++11 seem to imply the following usage:
std::allocator_traits<allocator_type>::allocate(100, ebo.prefix_ptr);
I guess this static allocate
member function will probably create a temporary ad-hoc instance of allocator_type
via its default constructor. But this leads to the following questions:
What will happen if allocator_type
is a stateful allocator? Will such allocators be able to keep their state if I use the static member functions in allocator_traits
instead of calling the non-static methods from an instance of allocator_type
?
Why should I instantiate allocator_type
at all and bother with stuff like EBO if I can directly use the static member functions in allocator_traits
instead?
As stated before, my understanding is that any class-like template parameters should be instantiated inside my container class in order to allow for stateful versions of these parameters. Is this understanding correct, and how does it fit with the static member functions in allocator_traits
?
On the other hand, the allocator_traits in C++11 seem to imply the following usage:
std::allocator_traits<allocator_type>::allocate(100, ebo.prefix_ptr);
No, you're missing the most important argument to that function call: the allocator.
I guess this static allocate member function will probably create a temporary ad-hoc instance of allocator_type via its default constructor.
No, because you pass an allocator argument to the function.
What will happen if allocator_type is a stateful allocator?
It works fine, because you pass that stateful allocator as an argument to the functions that use it.
Why should I instantiate allocator_type at all and bother with stuff like EBO if I can directly use the static member functions in allocator_traits instead?
Because you can't use them instead.
As stated before, my understanding is that any class-like template parameters should be instantiated inside my container class in order to allow for stateful versions of these parameters. Is this understanding correct, and how does it fit with the static member functions in allocator_traits?
Yes, your understanding is correct, and it fits fine with allocator_traits
if you use it properly.
The point of allocator_traits
is to provide sensible defaults for most of the Allocator interface. This has two purposes:
firstly it is simpler to define an allocator in C++11 (you only need to provide value_type
, allocate
, deallocate
, a template constructor for re-binding the allocator and operator==
and operator!=
) so writing simple custom allocators now is much simpler.
secondly it allows existing allocators that only meet the C++03 allocator requirements to be used by C++11 containers. C++03 allocators do not define the nested members such as propagate_on_container_swap
that C++11 containers look for, or the new variadic construct(pointer, Args&&...)
member that allows objects to be constructed with any arguments, not just copy constructed (which is what allows emplace
to work). So by wrapping use of allocators in allocator_traits
most of the Allocator interface is given sensible defaults, so that existing C++03 code using a custom allocator with a container such as std::vector
won't suddenly fail to build if recompiled using C++11. The std::vector
implementation only uses the new members through the allocator_traits
type and so it doesn't matter that the custom allocator wasn't updated to provide all the new members that are part of the C++11 Allocator requirements.
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