{"id":5112,"date":"2017-01-03T10:17:41","date_gmt":"2017-01-03T10:17:41","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/memory-management-with-std-allocator\/"},"modified":"2023-09-18T17:24:14","modified_gmt":"2023-09-18T17:24:14","slug":"memory-management-with-std-allocator","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/memory-management-with-std-allocator\/","title":{"rendered":"Memory Management with std::allocator"},"content":{"rendered":"<p>What is common between all containers of the Standard Template Library? They have a type parameter <span style=\"font-family: 'courier new', courier;\">Allocator<\/span> that is by default&nbsp;<span style=\"font-family: 'courier new', courier;\">std::allocator<\/span>. 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.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<\/p>\n<p>I write in this post about the containers of the Standard Template Library, but this includes <span style=\"font-family: 'courier new', courier;\">std::string<\/span>. For simplicity reasons, I will use the term container for both.<\/p>\n<p>What is special about <span style=\"font-family: 'courier new', courier;\">std<\/span>::<span style=\"font-family: courier new,courier;\">allocator<\/span>?<\/p>\n<p>On the one hand, it makes a difference if <span style=\"font-family: 'courier new', courier;\">std::allocator<\/span> allocates elements for a <span style=\"font-family: 'courier new', courier;\">std::vector<\/span> or pairs of<span style=\"font-family: 'courier new', courier;\"> std::map<\/span>.&nbsp;<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0000ff;\">template<\/span>&lt;\n    <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #2b91af;\">T<\/span>,\n    <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #2b91af;\">Allocator<\/span> = std::allocator&lt;T&gt;\n&gt; <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #2b91af;\">vector<\/span>;\n\n\n<span style=\"color: #0000ff;\">template<\/span>&lt;\n    <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #2b91af;\">Key<\/span>,\n    <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #2b91af;\">T<\/span>,\n    <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #2b91af;\">Compare<\/span> = std::less&lt;Key&gt;,\n    <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #2b91af;\">Allocator<\/span> = std::allocator&lt;std::pair&lt;<span style=\"color: #0000ff;\">const<\/span> Key, T&gt; &gt;\n&gt; <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #2b91af;\">map<\/span>;\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>On the other hand, an allocator needs a bunch of attributes, methods, and functions to do its job.<\/p>\n<h2>The interface<\/h2>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"> 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ Attributes<\/span>\nvalue_type                               T\npointer                                  T*\nconst_pointer                            <span style=\"color: #0000ff;\">const<\/span> T*\nreference                                T&amp;\nconst_reference                          <span style=\"color: #0000ff;\">const<\/span> T&amp;\nsize_type                                std::<span style=\"color: #2b91af;\">size_t<\/span>\ndifference_type                          std::<span style=\"color: #2b91af;\">ptrdiff_t<\/span>\npropagate_on_container_move_assignment   std::true_ty\nrebind                                   <span style=\"color: #0000ff;\">template<\/span>&lt; <span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #2b91af;\">U<\/span> &gt; <span style=\"color: #0000ff;\">struct<\/span> rebind { <span style=\"color: #0000ff;\">typedef<\/span> allocator&lt;U&gt; other; };\nis_always_equal                          std::true_type\n\n<span style=\"color: #008000;\">\/\/ Methods<\/span>\nconstructor\ndestructor\naddress\nallocate\ndeallocate\nmax_size\nconstruct\ndestroy\n\n<span style=\"color: #008000;\">\/\/ Functions<\/span>\n<span style=\"color: #0000ff;\">operator<\/span>==\n<span style=\"color: #0000ff;\">operator<\/span>!=\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p>In short, here are the essential members of&nbsp;<span style=\"font-family: courier new,courier;\">std::allocator&lt;T&gt;<\/span>.<\/p>\n<p>The inner class template <span style=\"font-family: 'courier new', courier;\">rebind<\/span> (line 10) is one of these important members. Thanks to the class template, you can rebind a<span style=\"font-family: 'courier new', courier;\"> std::allocator<\/span> of type T to a type U. The heart of <span style=\"font-family: 'courier new', courier;\">std::allocate<\/span> are the two methods <span style=\"font-family: 'courier new', courier;\">allocate<\/span> (line 17) and <span style=\"font-family: 'courier new', courier;\">deallocate<\/span> (line 18). Both methods manage the memory in which the object is initialized with <span style=\"font-family: 'courier new', courier;\">construct<\/span> (line 20) and destroyed with <span style=\"font-family: 'courier new', courier;\">destroy<\/span>&nbsp;(line 21). The method <span style=\"font-family: 'courier new', courier;\">max_size<\/span> (line 19) returns the maximum number of objects of type T for which <span style=\"font-family: 'courier new', courier;\">std::allocate<\/span> can allocate memory.&nbsp;<\/p>\n<p>Of course, you can directly use<span style=\"font-family: 'courier new', courier;\"> std::allocator<\/span>.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"> 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n24\n25\n26\n27\n28\n29\n30\n31\n32\n33\n34\n35\n36\n37\n38\n39\n40\n41\n42\n43\n44\n45\n46\n47\n48\n49<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ allocate.cpp<\/span>\n\n<span style=\"color: #0000ff;\">#include &lt;memory&gt;<\/span>\n<span style=\"color: #0000ff;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #0000ff;\">#include &lt;string&gt;<\/span>\n \n<span style=\"color: #2b91af;\">int<\/span> main(){\n  \n  std::cout &lt;&lt; std::endl;\n\n  std::allocator&lt;<span style=\"color: #2b91af;\">int<\/span>&gt; intAlloc; \n\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"intAlloc.max_size(): \"<\/span> &lt;&lt; intAlloc.max_size() &lt;&lt; std::endl;\n  <span style=\"color: #2b91af;\">int<\/span>* intArray = intAlloc.allocate(100);\n\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"intArray[4]: \"<\/span> &lt;&lt; intArray[4] &lt;&lt; std::endl;\n \n  intArray[4] = 2011;\n\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"intArray[4]: \"<\/span> &lt;&lt; intArray[4] &lt;&lt; std::endl;\n \n  intAlloc.deallocate(intArray, 100);\n\n  std::cout &lt;&lt; std::endl;\n \n  std::allocator&lt;<span style=\"color: #2b91af;\">double<\/span>&gt; doubleAlloc;\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"doubleAlloc.max_size(): \"<\/span> &lt;&lt; doubleAlloc.max_size() &lt;&lt; std::endl;\n  \n  std::cout &lt;&lt; std::endl;\n\n  std::allocator&lt;std::string&gt; stringAlloc;\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"stringAlloc.max_size(): \"<\/span> &lt;&lt; stringAlloc.max_size() &lt;&lt; std::endl;\n \n  std::string* myString = stringAlloc.allocate(3); \n \n  stringAlloc.construct(myString, <span style=\"color: #a31515;\">\"Hello\"<\/span>);\n  stringAlloc.construct(myString + 1, <span style=\"color: #a31515;\">\"World\"<\/span>);\n  stringAlloc.construct(myString + 2, <span style=\"color: #a31515;\">\"!\"<\/span>);\n \n  std::cout &lt;&lt; myString[0] &lt;&lt; <span style=\"color: #a31515;\">\" \"<\/span> &lt;&lt; myString[1] &lt;&lt; <span style=\"color: #a31515;\">\" \"<\/span> &lt;&lt; myString[2] &lt;&lt; std::endl;\n \n  stringAlloc.destroy(myString);\n  stringAlloc.destroy(myString + 1);\n  stringAlloc.destroy(myString + 2);\n  stringAlloc.deallocate(myString, 3);\n  \n  std::cout &lt;&lt; std::endl;\n  \n}\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p>I used in the program three allocators. One for an <span style=\"font-family: 'courier new', courier;\">int<\/span> (line 11), one for a&nbsp;<span style=\"font-family: 'courier new', courier;\">double<\/span> (line 26), and one for a <span style=\"font-family: 'courier new', courier;\">std::string<\/span> (line 31). Each allocator knows the maximum number of elements it can allocate (lines 14, 27, and 32).<\/p>\n<p>Now to the allocator for i<span style=\"font-family: courier new,courier;\">nt: std::allocator&lt;int&gt; intAlloc<\/span> (line 11). With&nbsp;<span style=\"font-family: courier new,courier;\">intAlloc<\/span>&nbsp;you can allocate an <span style=\"font-family: 'courier new', courier;\">int<\/span> 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&nbsp;<span style=\"font-family: courier new,courier;\">intAlloc.deallocate(intArray, 100)<\/span> (line 22) &nbsp;I deallocate the memory.&nbsp;&nbsp;<\/p>\n<p>The handling of the std::string allocator is more complex. The&nbsp;<span style=\"font-family: 'courier new', courier;\">stringAlloc.construct<\/span> calls in den lines 36 &#8211; 38 trigger three constructor calls for <span style=\"font-family: 'courier new', courier;\">std::string.<\/span> The three <span style=\"font-family: 'courier new', courier;\">stringAlloc.destroy<\/span> calls (lines 42 &#8211; 44) do the opposite. At the end (line 34), the memory of <span style=\"font-family: 'courier new', courier;\">myString<\/span> is released.<\/p>\n<p>And now the output of the program.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5111\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/01\/allocator.png\" alt=\"allocator\" style=\"margin: 15px;\" width=\"487\" height=\"288\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/01\/allocator.png 487w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/01\/allocator-300x177.png 300w\" sizes=\"auto, (max-width: 487px) 100vw, 487px\" \/><\/p>\n<h3>C++17<\/h3>\n<p>With C++17, the interface of <span style=\"font-family: 'courier new', courier;\">std::allocator<\/span> becomes a lot easier to handle. A lot of its members are deprecated.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"> 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n10\n11\n12\n13\n14<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ Attributes<\/span>\nvalue_type                               T\npropagate_on_container_move_assignment   std::true_ty\nis_always_equal                          std::true_type\n\n<span style=\"color: #008000;\">\/\/ Methods<\/span>\nconstructor\ndestructor\nallocate\ndeallocate\n\n<span style=\"color: #008000;\">\/\/ Functions<\/span>\n<span style=\"color: #0000ff;\">operator<\/span>==\n<span style=\"color: #0000ff;\">operator<\/span>!=\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p>But the key answer is this post is still missing.<\/p>\n<h2>Why does a container need an allocator?<\/h2>\n<p>I have three answers.<\/p>\n<ol>\n<li>The container should be <strong>independent of the underlying memory model<\/strong>. For example, the &nbsp;<a href=\"https:\/\/en.wikipedia.org\/wiki\/Intel_Memory_Model\">Intel Memory Model<\/a>&nbsp;on x86 architectures uses six variants:<em><span style=\"font-family: courier new,courier;\"><\/span><span style=\"font-family: courier new,courier;\">tiny, small, medium, compact, large,&nbsp;<\/span><\/em>and <em>huge<\/em>. I want to stress the point explicitly. I speak from the Intel Memory Model, not the memory model as the base of multithreading.<\/li>\n<li>The container can separate the <strong>memory allocation and deallocation from initializing and destroying their elements<\/strong>. Therefore, a call of&nbsp;<span style=\"font-family: courier new,courier;\">vec.reserve(n)<\/span>&nbsp;of a &nbsp;<span style=\"font-family: courier new,courier;\">std::vector vec<\/span>&nbsp;allocates only memory for at least n elements. The constructor for each element will not be executed. (<strong>Sven Johannsen<\/strong>)<\/li>\n<li>You can <strong>adjust the allocator of the container precisely to your needs.<\/strong> Therefore, the default allocators are optimized for not-so-frequent memory calls and big memory areas. Under the hood, the C function <span style=\"font-family: 'courier new', courier;\">std::malloc<\/span> 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. &nbsp;<\/li>\n<\/ol>\n<h2>What&#8217;s next?<\/h2>\n<p>Which strategies for requesting memory exist? That&#8217;s the question I want to answer in the<a href=\"https:\/\/www.modernescpp.com\/index.php\/strategies-for-the-allocation-of-memory\"> next post.<\/a><span id=\"transmark\"><\/span><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<a href=\"https:\/\/github.com\/RainerGrimm\/ModernesCppSource\"><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>What is common between all containers of the Standard Template Library? They have a type parameter Allocator that is by default&nbsp;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.<\/p>\n","protected":false},"author":21,"featured_media":5111,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[364],"tags":[556,498,493],"class_list":["post-5112","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-embedded","tag-allocator","tag-memory","tag-new-delete"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5112","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=5112"}],"version-history":[{"count":2,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5112\/revisions"}],"predecessor-version":[{"id":8287,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5112\/revisions\/8287"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5111"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5112"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5112"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5112"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}