The job of an allocator is to obtain "raw" memory via its allocate
method. What the caller constructs in the memory returned by the allocator is of no concern to the allocator (right?). So why is std::allocator
a template when this only seems to add unnecessary complexity? What does the allocator actually do with that type information? Why does it have to know the type of object the memory is for? I'm assuming that there is some obvious reason that I'm missing, so what is that reason?
std::allocator is the default memory allocator for the standard library containers, and you can substitute your own allocators. This allows you to control how the standard containers allocate memory.
Allocators are used by the C++ Standard Library to handle the allocation and deallocation of elements stored in containers. All C++ Standard Library containers except std::array have a template parameter of type allocator<Type> , where Type represents the type of the container element.
Allocators are objects responsible for encapsulating memory management. std::allocator is used when you want to separate allocation and do construction in two steps. It is also used when separate destruction and deallocation is done in two steps.
A Pool allocator (or simply, a Memory pool) is a variation of the fast Bump-allocator, which in general allows O(1) allocation, when a free block is found right away, without searching a free-list. To achieve this fast allocation, usually a pool allocator uses blocks of a predefined size.
Well, std::allocator
, and the Allocator concept itself, were invented to deal with issues like near- and far-pointers, or generally pointers to different address-spaces. And they deal with that ... adequately. The allocator determines the pointer-type used.
They can also be used to deal with different memory-allocators, though the amount of boilerplate for that is somewhat staggering.
And finally, an allocator-aware container can coupled with an allocator taking advantage of that provide a sub-allocator to child-elements, which might help reduce overhead.
The first point is nowadays mostly obsolete, though it can be used with the second point to have a mapping-address-invariant container in a shared memory segment, or a file.
The second point can be used for taking advantage of specialized allocators, though the interface is not really good for that. An example where I used it to hack me a secure std::basic_string
.
And the last point is rarely used.
The one huge disadvantage of the Allocator concept as defined is the fact that it uses a template. All use already goes through std::allocator_traits<Allocator>
, so it just leads to types inadvertently being almost the same, were there not the template-argument to the allocator.
And also to much duplicated code to rebind the allocator appropriately.
Alignment comes to mind. Different types have different alignment requirements, a memory location that is good for a char
array may not be good for a double
(which generally require 8-byte aligned addresses).
OTOH, it should be noted that malloc
solves this problem by providing memory that have a correct alignment for the most stringent of the built-in types, which is generally a good enough solution for a general-purpose allocator.
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