According to C++ Primer 4th edition, page 755, there is a note saying:
Modern C++ programs ordinarily ought to use the allocator class to allocate memory. It is safer and more flexible.
I don't quite understand this statement. So far all the materials I read teach using new
to allocate memory in C++. An example of how vector class utilize allocator is shown in the book. However, I cannot think of other scenarios.
Can anyone help to clarify this statement? and give me more examples? When should I use allocator and when to use new
? Thanks!
allocator is the memory allocator for the STL containers. This container can separate the memory allocation and de-allocation from the initialization and destruction of their elements. Therefore, a call of vec. reserve(n) of a vector vec allocates only memory for at least n elements.
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.
Struct std::alloc::System The default memory allocator provided by the operating system. This is based on malloc on Unix platforms and HeapAlloc on Windows, plus related functions. It can also be used directly to allocate memory independently of whatever global allocator has been selected for a Rust program.
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.
For general programming, yes you should use new
and delete
.
However, if you are writing a library, you should not! I don't have your textbook, but I imagine it is discussing allocators in the context of writing library code.
Users of a library may want control over exactly what gets allocated from where. If all of the library's allocations went through new
and delete
, the user would have no way to have that fine-grained level of control.
All STL containers take an optional allocator template argument. The container will then use that allocator for its internal memory needs. By default, if you omit the allocator, it will use std::allocator
which uses new
and delete
(specifically, ::operator new(size_t)
and ::operator delete(void*)
).
This way, the user of that container can control where memory gets allocated from if they desire.
Example of implementing a custom allocator for use with STL, and explanation: Improving Performance with Custom Pool Allocators for STL
Side Note: The STL approach to allocators is non-optimal in several ways. I recommend reading Towards a Better Allocator Model for a discussion of some of those issues.
Edit in 2019: The situation in C++ has improved since this answer was written. Stateful allocators are supported in C++11, and that support was improved in C++17. Some of the people involved in the "Towards a Better Allocator Model" were involved in those changes (eg: N2387), so that's nice (:
The two are not contradictory. Allocators are a PolicyPattern or StrategyPattern used by the STL libraries' container adapters to allocate chunks of memory for use with objects.
These allocators frequently optimize memory allocation by allowing * ranges of elements to be allocated at once, and then initialized using a placement new * items to be selected from secondary, specialized heaps depending on blocksize
One way or another, the end result will (almost always) be that the objects are allocated with new (placement or default)
Another vivid example would be how e.g. boost library implements smartpointers. Because smartpointers are very small (with little overhead) the allocation overhead might become a burden. It would make sense for the implementation to define a specialized allocator to do the allocations, so one may have efficient std::set<> of smartpointers, std::map<..., smartpointer> etc.
(Now I'm almost sure that boost actually optimizes storage for most smartpointers by avoiding any virtuals, therefore the vft, making the class a POD structure, with only the raw pointer as storage; some of the example will not apply. But then again, extrapolate to other kinds of smartpointer (refcounting smartpointers, pointers to member functions, pointers to member functions with instance reference etc. etc.))
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