{"id":5084,"date":"2016-12-16T18:58:05","date_gmt":"2016-12-16T18:58:05","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/automatic-memory-management-with-containers\/"},"modified":"2023-06-26T12:31:56","modified_gmt":"2023-06-26T12:31:56","slug":"automatic-memory-management-with-containers","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/automatic-memory-management-with-containers\/","title":{"rendered":"Automatic Memory Management of the STL Containers"},"content":{"rendered":"<p>One of the significant advantages of a C++ string to a C string and of a <span style=\"font-family: courier new,courier;\">std::vector<\/span> to a C array is that both C++ containers automatically manage their memory. Of course, that holds for all further containers of the Standard Template Library. In this post, I will look closer at the automatic memory management of <span style=\"font-family: courier new,courier;\">std::vector<\/span> and <span style=\"font-family: courier new,courier;\">std::string.<\/span><\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<\/p>\n<p>From the user&#8217;s perspective, a <span style=\"font-family: courier new,courier;\">std::string<\/span> in C++11 feels like a <span style=\"font-family: courier new,courier;\">std::vector.<\/span> That is the simple reason I can present them in parallel. Therefore, it fits very well that std::string and std::vector are the essential containers in C++.<\/p>\n<h2>std::string and std::vector<\/h2>\n<p>The C++ runtime automatically adjusts the size of a <span style=\"font-family: courier new,courier;\">std::string<\/span> and <span style=\"font-family: courier new,courier;\">std::vector<\/span> to its number of elements. And with C++11 in both directions.<\/p>\n<p>&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<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"> 1\r\n 2\r\n 3\r\n 4\r\n 5\r\n 6\r\n 7\r\n 8\r\n 9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\n25\r\n26\r\n27\r\n28\r\n29\r\n30\r\n31\r\n32\r\n33\r\n34\r\n35\r\n36\r\n37\r\n38\r\n39\r\n40\r\n41\r\n42\r\n43\r\n44\r\n45\r\n46\r\n47\r\n48\r\n49\r\n50\r\n51\r\n52\r\n53\r\n54\r\n55\r\n56\r\n57\r\n58\r\n59\r\n60\r\n61\r\n62\r\n63\r\n64\r\n65\r\n66\r\n67\r\n68\r\n69<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ stringAndVector.cpp<\/span>\r\n\r\n<span style=\"color: #0000ff;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;string&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;vector&gt;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">template<\/span> &lt;<span style=\"color: #0000ff;\">typename<\/span> T&gt;\r\n<span style=\"color: #2b91af;\">void<\/span> showInfo(<span style=\"color: #0000ff;\">const<\/span> T&amp; t,<span style=\"color: #0000ff;\">const<\/span> std::string&amp; name){\r\n\r\n  std::cout &lt;&lt; name &lt;&lt; <span style=\"color: #a31515;\">\" t.size(): \"<\/span> &lt;&lt; t.size() &lt;&lt; std::endl;\r\n  std::cout &lt;&lt; name &lt;&lt; <span style=\"color: #a31515;\">\" t.capacity(): \"<\/span> &lt;&lt; t.capacity() &lt;&lt; std::endl;\r\n\r\n}\r\n\r\n<span style=\"color: #2b91af;\">int<\/span> main(){\r\n    \r\n  std::cout &lt;&lt; std::endl;\r\n\r\n  std::string str;\r\n  std::vector&lt;<span style=\"color: #2b91af;\">int<\/span>&gt; vec;\r\n  \r\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"Maximal size: \"<\/span> &lt;&lt; std::endl;\r\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"str.max_size(): \"<\/span> &lt;&lt; str.max_size() &lt;&lt; std::endl;\r\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"vec.max_size(): \"<\/span> &lt;&lt; vec.max_size() &lt;&lt; std::endl;\r\n  std::cout &lt;&lt; std::endl;\r\n  \r\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"Empty string and vector: \"<\/span> &lt;&lt; std::endl;\r\n  showInfo(str,<span style=\"color: #a31515;\">\"String\"<\/span>);\r\n  showInfo(vec,<span style=\"color: #a31515;\">\"Vector\"<\/span>);\r\n  std::cout &lt;&lt; std::endl;\r\n  \r\n  \r\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"Initialized with five values: \"<\/span> &lt;&lt; std::endl;\r\n  str= {<span style=\"color: #a31515;\">\"12345\"<\/span>};\r\n  vec= {1,2,3,4,5};\r\n  showInfo(str,<span style=\"color: #a31515;\">\"String\"<\/span>);\r\n  showInfo(vec,<span style=\"color: #a31515;\">\"Vector\"<\/span>);\r\n  std::cout &lt;&lt; std::endl;\r\n  \r\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"Added four additional values: \"<\/span> &lt;&lt; std::endl;\r\n  str += <span style=\"color: #a31515;\">\"6789\"<\/span>;\r\n  vec.insert(vec.end(),{6,7,8,9});\r\n  showInfo(str,<span style=\"color: #a31515;\">\"String\"<\/span>);\r\n  showInfo(vec,<span style=\"color: #a31515;\">\"Vector\"<\/span>);\r\n  std::cout &lt;&lt; std::endl;\r\n  \r\n  \r\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"Resized to 30 values: \"<\/span> &lt;&lt; std::endl;\r\n  str.resize(30);\r\n  vec.resize(30);\r\n  showInfo(str,<span style=\"color: #a31515;\">\"String\"<\/span>);\r\n  showInfo(vec,<span style=\"color: #a31515;\">\"Vector\"<\/span>);\r\n  std::cout &lt;&lt; std::endl;\r\n\r\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"Reserved space for at least 1000 values: \"<\/span> &lt;&lt; std::endl;\r\n  str.reserve(1000);\r\n  vec.reserve(1000);\r\n  showInfo(str,<span style=\"color: #a31515;\">\"String\"<\/span>);\r\n  showInfo(vec,<span style=\"color: #a31515;\">\"Vector\"<\/span>);\r\n  std::cout &lt;&lt; std::endl;\r\n  \r\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"Shrinked to the current size: \"<\/span> &lt;&lt; std::endl;\r\n  str.shrink_to_fit();\r\n  vec.shrink_to_fit();\r\n  showInfo(str,<span style=\"color: #a31515;\">\"String\"<\/span>);\r\n  showInfo(vec,<span style=\"color: #a31515;\">\"Vector\"<\/span>);\r\n  std::cout &lt;&lt; std::endl;\r\n\r\n}\r\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The program is relatively easy to get. That was my first thought. But wait for a second.<\/p>\n<p>To spare typing, I wrote the small function <span style=\"font-family: courier new,courier;\">showInfo<\/span> (lines 7 &#8211; 13). This function returns for a container its size (line 10) and capacity (line 11). The size of a container is its number of elements, and the capacity of a container is the number of elements a container can hold without an additional allocation. Therefore, the capacity of the container has at least to be as big as its size. You can adjust the size of a container with its method <span style=\"font-family: courier new,courier;\">resize<\/span> (lines 49 and 50); you can adjust the capacity of a container with its method <span style=\"font-family: courier new,courier;\">reserve<\/span> (lines 56 and 57).<\/p>\n<\/p>\n<p style=\"text-align: left;\">But, back to the program from top to bottom. I create in lines 19 and 20 an empty string and an empty vector. Afterward, the program displays the maximum number of elements a string or vector can have. After each operation on both containers, it returns their size and capacity. That holds for the initialization of the containers (lines 34 and 35), for the addition of four new elements (lines 42 and 43), the resizing of the containers to 30 elements (lines 49 and 50), and the reserving of additional memory for at least 1000 elements (line 56 and 57). With C++11, you can shrink the container&#8217;s capacity to its size with the method shrink_to_fit (lines 63 and 64).<\/p>\n<p>Before I present the program&#8217;s output on Linux and Windows, let me make a few observations.<\/p>\n<ol>\n<li>Adjusting the size and capacity of the container is done automatically. I haven&#8217;t used any memory operations like <span style=\"font-family: courier new,courier;\">new<\/span> and <span style=\"font-family: courier new,courier;\">delete.<\/span><\/li>\n<li><span style=\"font-family: courier new,courier;\">std::string<\/span> and <span style=\"font-family: courier new,courier;\">std::vector<\/span> support the same interface. The only exception to this rule is line 41. Here I added a C string to a C++ string.<\/li>\n<li>By using the method <span style=\"font-family: courier new,courier;\">cont.resize(n)<\/span>, the container <span style=\"font-family: courier new,courier;\">cont<\/span> will get new default-initialized elements if<span style=\"font-family: courier new,courier;\"> <\/span><span style=\"font-family: courier new,courier;\">n &gt; cont.size()<\/span> is accurate.<\/li>\n<li>By using the method <span style=\"font-family: courier new,courier;\">cont.reserve(n)<\/span>, the container <span style=\"font-family: courier new,courier;\">cont<\/span> will be get new memory for at least n elements if<span style=\"font-family: courier new,courier;\"> <\/span><span style=\"font-family: courier new,courier;\">n &gt; cont.capacity()<\/span> is true.<\/li>\n<li>The call <span style=\"font-family: courier new,courier;\">shrink_to_fit<\/span> is non-binding. That means the C++ runtime has not have to adjust the capacity of a container to its size. But, my usages of the method <span style=\"font-family: courier new,courier;\">shrink_to_fit<\/span> with GCC, clang, or cl.exe always freed the unnecessary memory.<\/li>\n<\/ol>\n<p>Here is the output of the program.<\/p>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5079\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/stringAndVector.png\" alt=\"stringAndVector\" width=\"350\" height=\"585\" style=\"margin: 15px;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/stringAndVector.png 448w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/stringAndVector-180x300.png 180w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5080\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/stringAndVectorWin.png\" alt=\"stringAndVectorWin\" width=\"350\" height=\"622\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/stringAndVectorWin.png 559w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/stringAndVectorWin-169x300.png 169w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/p>\n<h3>My little astonishment<\/h3>\n<p>The program shows that the MSVC 15 STL implementation is slightly more greedy than the GCC 4.8 STL implementation. That holds, in particular, true for <span style=\"font-family: courier new,courier;\">std::string.<\/span> Therefore, the empty <span style=\"font-family: courier new,courier;\">std::string<\/span> has 15 elements. But I was more astonished that the maximum size of a <span style=\"font-family: courier new,courier;\">std::string<\/span> is as big as the maximum size of a <span style=\"font-family: courier new,courier;\">std::vector&lt;int&gt; <\/span>on Linux. This is astonishing because an <span style=\"font-family: courier new,courier;\">int<\/span> is four times as big as a <span style=\"font-family: courier new,courier;\">char<\/span> on Linux and Windows.<span style=\"font-family: courier new,courier;\"><\/span><span style=\"font-family: courier new,courier;\"><\/span><span style=\"font-family: courier new,courier;\"> <br \/><\/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<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0000ff;\">#include &lt;iostream&gt;<\/span>\r\n\r\n<span style=\"color: #2b91af;\">int<\/span> main(){\r\n    \r\n  std::cout &lt;&lt; std::endl;\r\n\r\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"sizeof(char): \"<\/span> &lt;&lt; <span style=\"color: #0000ff;\">sizeof<\/span>(<span style=\"color: #2b91af;\">char<\/span>) &lt;&lt; std::endl;\r\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"sizeof(int): \"<\/span> &lt;&lt; <span style=\"color: #0000ff;\">sizeof<\/span>(<span style=\"color: #2b91af;\">int<\/span>) &lt;&lt; std::endl;\r\n  \r\n  std::cout &lt;&lt; std::endl;\r\n\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5081\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/sizeof.png\" alt=\"sizeof\" width=\"350\" height=\"164\" style=\"margin: 15px;\" \/><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5082\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/sizeofWin.png\" alt=\"sizeofWin\" width=\"300\" height=\"192\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/sizeofWin.png 509w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/sizeofWin-300x192.png 300w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>You have to interpret both values as maximum values. Any ideas on the discrepancy?<\/p>\n<h3>My astonishment has disappeared<\/h3>\n<p>Thanks to the help of Mark Abraham and Cl\u00e9ment Gregoire, the riddle is solved.<\/p>\n<h4>Microsoft implementation is more greedy<\/h4>\n<p>Microsoft Visuals <span style=\"font-family: courier new,courier;\">std::string<\/span> implementation uses internally small string optimization. Therefore, a small string needs no heap allocation and goes directly to the stack. The boundary is exactly 15 characters. GCC will get a conformant string implementation with 5.1. But I used GCC 4.8 in my test.<\/p>\n<h4>GCC with conformant std::string implementation<\/h4>\n<p>&nbsp;If I use GCC 5.3 with a conformant <span style=\"font-family: courier new,courier;\">std::string i<\/span>mplementation, the picture will differ.<\/p>\n<p>&nbsp;<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5083\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/stringAndVectorGCC5_3.png\" alt=\"stringAndVectorGCC5 3\" width=\"700\" height=\"682\" style=\"margin: 15px;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/stringAndVectorGCC5_3.png 757w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/12\/stringAndVectorGCC5_3-300x292.png 300w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/p>\n<p>To use the conformant <span style=\"font-family: courier new,courier;\">std::string<\/span> implementation in GCC 5.3,&nbsp; I must use the compiler flag <span id=\"hs_cos_wrapper_post_body\" class=\"hs_cos_wrapper hs_cos_wrapper_meta_field hs_cos_wrapper_type_rich_text\" data-hs-cos-general-type=\"meta_field\" data-hs-cos-type=\"rich_text\"><span style=\"font-family: courier new,courier;\">-D_GLIBCXX_USE_CXX11_ABI=1.<\/span> Now, the maximum size of<span style=\"font-family: courier new,courier;\"> <span style=\"font-family: courier new,courier;\">std::string<\/span> <\/span>is two times that of<span style=\"font-family: courier new,courier;\"> <span style=\"font-family: courier new,courier;\">std::vector&lt;int&gt;.<\/span><\/span> The C++11 standard says about <span style=\"font-family: courier new,courier;\"><span style=\"font-family: courier new,courier;\">max_size(): &#8220;<em>The size of the largest possible string.<\/em>&#8221; <\/span><\/span>Now, I&#8217;m fine.<span style=\"font-family: courier new,courier;\"> <\/span><\/span><\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>I will have in the<a href=\"https:\/\/www.modernescpp.com\/index.php\/std-array-dynamic-memory-no-thanks\"> next post<\/a><span id=\"transmark\"> <\/span>a closer look at <span style=\"font-family: courier new,courier;\">std::array. std::array<\/span> combines the best of two worlds. On the one hand, <span style=\"font-family: courier new,courier;\">std::array<\/span> is as lightweight as a C array; on the other hand, <span style=\"font-family: courier new,courier;\">std::array<\/span> supports the same interface as a <span style=\"font-family: courier new,courier;\">std::vector.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>One of the significant advantages of a C++ string to a C string and of a std::vector to a C array is that both C++ containers automatically manage their memory. Of course, that holds for all further containers of the Standard Template Library. In this post, I will look closer at the automatic memory management [&hellip;]<\/p>\n","protected":false},"author":21,"featured_media":5079,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[364],"tags":[498],"class_list":["post-5084","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-embedded","tag-memory"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5084","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=5084"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5084\/revisions"}],"predecessor-version":[{"id":6912,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5084\/revisions\/6912"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5079"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5084"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5084"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5084"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}