I\'ve just read about std::allocator
. In my opinion, it is more complicated to use it instead of using new
and delete
.
With <
The reason for this STL member is to give the developer more control over memory. What I mean by this is, for instance, the new operator is not really just one operation per se. At its most basic, it performs a reservation of memory AND then fills that space with the object.
Although I cannot on top of my head come up with a specific, real-world case scenario, you should use std::allocator
and such when, perhaps, the destruction of a given object might impact other objects in memory.
Let's say, for the sake of argument, you created some kind of vector which each element is double-linked to some other object in memory and you want, at the time of deletion of said vector, the objects linked to remove the reference back to it.
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 about std::allocator
specifically, but rather the strategy of allocating memory, then constucting objects in that memory, rather than using new 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
used new 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 objects std::vector
can hold.
You are confused. std::allocator
calls/uses new
and delete
. It is simply another level in the C++ memory hierarchy, used to serve the various needs of the C++ standard library, particularly the containers, but other types too. The C++ library containers use the allocator to automatically manage the memory of the contained elements. Without it, things would be more cumbersome and thus more difficult to use. Furthermore an allocator can be used to perform different techniques of memory management, eg stack allocation, linear allocation, heap allocation, pool allocation etc.
C++ memory "hierarchy"
_________________
|Applications |
|_______________|
|
______↓_______________________
|C++ library (std::allocator)|
|____________________________|
|
______↓______________________________________________________________________________
|C++ primitives (new/delete, new[]/delete[], ::operator new()/::operator delete()) |
|___________________________________________________________________________________|
|
______↓______
|malloc/free|
|___________|
|
______↓______________
|OS APIs, syscalls |
|___________________|
This is the normal flow of calls, but an application can instead call malloc/free, or new/delete or even the OS APIs directly. You see it's ALL an abstraction. The level above abstracts the more difficult nature of the one and wraps it in an easier to use package.
new
and delete
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.
With allocator we must explicitly allocate heap memory, construct it, destroy it, and then finally deallocate the memory.
Indeed allocators are not supposed to be used for "normal" code where new
and delete
would equally be fine. Consider a class like std::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
and delete
.
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 is class 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. Since new
and delete
are functions and not classes, it is necessary to have the std::allocator
to represent them and make them valid template arguments.