What is common between all containers of the Standard Template Library? They have a type parameter Allocator that is by default std::allocator. The job of the allocator is to manage the lifetime of its elements. That means allocating and deallocating memory for its elements and initializing and destroying them.
I write in this post about the containers of the Standard Template Library, but this includes std::string. For simplicity reasons, I will use the term container for both.
What is special about std::allocator?
On the one hand, it makes a difference if std::allocator allocates elements for a std::vector or pairs of std::map.
On the other hand, an allocator needs a bunch of attributes, methods, and functions to do its job.
In short, here are the essential members of std::allocator<T>.
The inner class template rebind (line 10) is one of these important members. Thanks to the class template, you can rebind a std::allocator of type T to a type U. The heart of std::allocate are the two methods allocate (line 17) and deallocate (line 18). Both methods manage the memory in which the object is initialized with construct (line 20) and destroyed with destroy (line 21). The method max_size (line 19) returns the maximum number of objects of type T for which std::allocate can allocate memory.
Of course, you can directly use std::allocator.
I used in the program three allocators. One for an int (line 11), one for a double (line 26), and one for a std::string (line 31). Each allocator knows the maximum number of elements it can allocate (lines 14, 27, and 32).
Now to the allocator for int: std::allocator<int> intAlloc (line 11). With intAlloc you can allocate an int array of 100 elements (line 14). The access to the 5th element is not defined because, firstly, it has to be initialized. That changes in line 20. Thanks to the call intAlloc.deallocate(intArray, 100) (line 22) I deallocate the memory.
The handling of the std::string allocator is more complex. The stringAlloc.construct calls in den lines 36 – 38 trigger three constructor calls for std::string. The three stringAlloc.destroy calls (lines 42 – 44) do the opposite. At the end (line 34), the memory of myString is released.
And now the output of the program.
With C++17, the interface of std::allocator becomes a lot easier to handle. A lot of its members are deprecated.
But the key answer is this post is still missing.
Why does a container need an allocator?
I have three answers.
- The container should be independent of the underlying memory model. For example, the Intel Memory Model on x86 architectures uses six variants:tiny, small, medium, compact, large, and huge. I want to stress the point explicitly. I speak from the Intel Memory Model, not the memory model as the base of multithreading.
- The container can separate the memory allocation and deallocation from initializing and destroying their elements. Therefore, a call of vec.reserve(n) of a std::vector vec allocates only memory for at least n elements. The constructor for each element will not be executed. (Sven Johannsen)
- You can adjust the allocator of the container precisely to your needs. Therefore, the default allocators are optimized for not-so-frequent memory calls and big memory areas. Under the hood, the C function std::malloc will typically be used. Therefore, an allocator using preallocated memory can significantly boost performance. An adjusted allocator also makes a lot of sense if you need a deterministic timing behavior for your program. With the default allocator of a container, you have no guarantee of how long a memory allocation will take. Of course, you can use an adjusted allocator to give you enriched debugging information.
Which strategies for requesting memory exist? That’s the question I want to answer in the next post.
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, and Marco Parri Empoli.
Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.
|My special thanks to Embarcadero|
|My special thanks to PVS-Studio|
|My special thanks to Tipi.build|
|My special thanks to Take Up Code|
I’m happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.
- Embedded Programmierung mit modernem C++ 12.12.2023 – 14.12.2023 (Präsenzschulung, Termingarantie)
Standard Seminars (English/German)
Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.
- C++ – The Core Language
- C++ – The Standard Library
- C++ – Compact
- C++11 and C++14
- Concurrency with Modern C++
- Design Pattern and Architectural Pattern with C++
- Embedded Programming with Modern C++
- Generic Programming (Templates) with C++
- Clean Code with Modern C++
- Phone: +49 7472 917441
- Mobil:: +49 176 5506 5086
- Mail: schulung@ModernesCpp.de
- German Seminar Page: www.ModernesCpp.de
- Mentoring Page: www.ModernesCpp.org
Modernes C++ Mentoring,