I've just read about std::allocator
. In my opinion, it is more complicated to use it instead of using new
and delete
.
With allocator
we must explicitly allocate heap memory, construct it, destroy it, and then finally deallocate the memory. So why was it created?
In which cases can it be used and when should it be used instead of new and delete?
new
anddelete
are the direct way to create an object in dynamic memory and initialize it. Allocators are much more though, because they offer complete control over the aforementioned phases.Indeed allocators are not supposed to be used for "normal" code where
new
anddelete
would equally be fine. Consider a class likestd::map
, often implemented as a tree: do you need to deallocate the whole leaf whenever an object held is deleted? Allocators allow you do destruct that object, but keep the memory so that you don't have to require it again.Further, you may specialize an allocator for a certain type if you know more optimized methods for its control which is not possible for
new
anddelete
.Allocators are a very important concept in the STL. Every container is capable to take an allocator as argument. Then allocations will be performed using this allocator, and not the standard one.
This is useful e.g. for allocating objects of the same size in a pool, to improve performance, or might be necessary if there's a special area of memory where your objects need to live.
The steps of allocating and constructing are separate because e.g. for vector (
std::vector::reserve
) it's important to be able to allocate memory for future use, but not (yet) create objects therein.As an example you could write an allocator as a class, containing an fixed size array, and use that array to provide memory for some standard container. Then you can have an instance of that class on the stack and thus completely avoid heap allocations for some part of your programm.
See more examples here in this SO post.
When you have specific needs, and most important when writing own generic containers.
The
std::allocator
was created to allow developers more control of how memory is allocated. In many embedded systems, memory is constrained and in different types. There may not be a huge amount. Also, memory allocation wants to be minimized to avoid fragmentation issues.The allocator also allows for allocation from different memory pools. So for example, allocating small sized blocks would be more efficient from a small block memory pool.
Your instinct is right. In 90% of cases, use
new
. However, notice in structures like, say, the map data structure. One of its default template arguments isclass Alloc = allocator<pair<const Key,T>
, which defines how the class creates new instances of things and manages existing instances. In this way, you could theoretically create your own allocator and then use it for existing data structures. Sincenew
anddelete
are functions and not classes, it is necessary to have thestd::allocator
to represent them and make them valid template arguments.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. But I don't think that your question is aboutstd::allocator
specifically, but rather the strategy of allocating memory, then constucting objects in that memory, rather than usingnew T[N]
, for example.And the reason for that is that
new T[N]
doesn't allow you control over what constructors are called. And it forces you to construct all your objects at the same time. This is terrible for the purposes of, for example,std::vector
where you only want to allocate occasionally.With a raw memory allocator, you can allocate a certain amount of memory, which determines your capacity. Then, as the user adds items to the vector (using the constructor of their choice), you can construct objects in place in this memory.
Then when you run out of memory, you allocate more, typically twice as much. If
std::vector
usednew T[N]
, it would have to reallocate every time you wanted to add or remove an element, which would be terrible for performance. You would also be forced to use the default constructor for all the objects, which puts an unnecessary restriction on the types of objectsstd::vector
can hold.Yes, but it is not meant to replace
new
anddelete
, it serves a different purpose.Because sometimes you want to separate allocation and construction into two steps (and similarly to separate destruction and deallocation into two steps). If you don't want to do that, don't use an allocator, use
new
instead.When you need the behaviour of an allocator, not the behaviour of
new
anddelete
, obviously! The typical case is when implementing a container.Consider the following code:
Here line (1) must allocate enough memory for four objects, but not construct them yet. Then lines (2) and (3) must construct objects into the allocated memory. Then line (4) must destroy those objects, but not deallocate the memory. Finally, in the vector's destructor, all the memory can be deallocated.
So the vector cannot just use
new X()
ordelete &m_data[1]
to create and destroy the objects, it must perform allocation/deallocation separately from construction/destruction. A container's allocator template argument defines the policy that should be used for (de)allocating memory and constructing/destructing objects, allowing the container's use of memory to be customised. The default policy is thestd::allocator
type.So you use an allocator when an allocator is required (such as when using a container) and you use
std::allocator
when you don't want to provide a custom allocator and just want the standard one.You don't use an allocator as a replacement for
new
anddelete
.