Codeguru has a good article: http://www.codeguru.com/cpp/cpp/cpp_mfc/stl/article.php/c4079
Part Of it:
As you (hopefully) have learned in the first article, a 'std::vector'
is a replacement for an old ANSI C array. The following code should look familiar to many developers:
int *Array = (int *) malloc(100 * sizeof(int));
It will simply allocate memory for storing 100 integers. 'malloc()'
will allocate the requested amount of memory from the heap. Thus, after you are done with it, you have to explicitly release the memory by a call to 'free()'
:
if(Array)
free(Array);
In C++, this error-prone approach is no longer necessary using the container 'std::vector'
from the STL:
#include <vector>
std::vector<int> Array(100);
As you can see, there is no explicit request for memory allocation involved. All the necessary memory allocation will be done by the 'std::vector'
itself...implicitly. And yes, as you already might have guessed, the whole memory management is done through the so-called allocator.
If you think about how you usually allocate memory dynamically (using the 'new'
operator), you could ask why the STL provides such a thing called allocator that does all the memory management of the container classes. The concept of allocators was originally introduced to provide an abstraction for different memory models to handle the problem of having different pointer types on certain 16-bit operating systems (such as near, far, and so forth). However, this approach failed. Nowadays, allocators serve as an abstraction to translate the need to use memory into a raw call for memory.
Thus, allocators simply separate the implementation of containers, which need to allocate memory dynamically, from the details of the underlying physical memory management. Thus, you can simply apply different memory models such as shared memory, garbage collections, and so forth to your containers without any hassle because allocators provide a common interface.
To completely understand why allocators are an abstraction, you have to think about how they are integrated into the container classes. If you take a look at the constructor of 'std::vector'
:
vector<T, Alloc>
you will notice that two template parameters exist. 'T' represents the vector's value type—in other words, the type of object that is stored in the vector. 'Alloc' represents the vector's allocator—in other words, the method for the internal memory management.
The internal implementation of the allocator is completely irrelevant to the vector itself. It is simply relying on the standardized public interface every allocator has to provide. The vector does not need to care any longer whether it would need to call 'malloc'
, 'new'
, and so on to allocate some memory; it simply calls a standardized function of the allocator object named 'allocate()'
that will simply return a pointer to the newly allocated memory. Whether this function internally uses 'malloc'
, 'new'
, or something else, is not of any interest to the vector.
After reading the background and purpose of allocators, you might wonder whether you need to provide your own allocator every time you want to use a container from the STL. You can breathe a sigh of relief...you do not have to. The standard provides an allocator that internally uses the global operators 'new'
and 'delete'
. It is defined within the header file <memory> and is used as the default one everywhere an allocator is needed.
The default allocator that comes with your implementation of the STL will do a very good job in nearly all cases. That is not surprising because the implementations of the STL are written by very experienced people. In other words, the assumption of being able to write an allocator that outperforms the standard one in the general case is at least questionable. So, why implement an allocator on your own in the first place?
There are a couple of reasons justifying that:
'allocator'
for a well-defined, particular task. In this case, your a-priori knowledge about the allocation/deallocation behavior of your code enables you to design an 'allocator'
that is faster than the default one.