Automatic Memory Management of the STL Containers

Contents[Show]

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 of std::vector and std::string.

 

From the user's perspective, a std::string in C++11 feels like a std::vector. 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++.

std::string and std::vector

The C++ runtime automatically adjusts the size of a std::string and std::vector to its number of elements. And with C++11 in both directions.

 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// stringAndVector.cpp

#include <iostream>
#include <string>
#include <vector>

template <typename T>
void showInfo(const T& t,const std::string& name){

  std::cout << name << " t.size(): " << t.size() << std::endl;
  std::cout << name << " t.capacity(): " << t.capacity() << std::endl;

}

int main(){
    
  std::cout << std::endl;

  std::string str;
  std::vector<int> vec;
  
  std::cout << "Maximal size: " << std::endl;
  std::cout << "str.max_size(): " << str.max_size() << std::endl;
  std::cout << "vec.max_size(): " << vec.max_size() << std::endl;
  std::cout << std::endl;
  
  std::cout << "Empty string and vector: " << std::endl;
  showInfo(str,"String");
  showInfo(vec,"Vector");
  std::cout << std::endl;
  
  
  std::cout << "Initialized with five values: " << std::endl;
  str= {"12345"};
  vec= {1,2,3,4,5};
  showInfo(str,"String");
  showInfo(vec,"Vector");
  std::cout << std::endl;
  
  std::cout << "Added four additional values: " << std::endl;
  str += "6789";
  vec.insert(vec.end(),{6,7,8,9});
  showInfo(str,"String");
  showInfo(vec,"Vector");
  std::cout << std::endl;
  
  
  std::cout << "Resized to 30 values: " << std::endl;
  str.resize(30);
  vec.resize(30);
  showInfo(str,"String");
  showInfo(vec,"Vector");
  std::cout << std::endl;

  std::cout << "Reserved space for at least 1000 values: " << std::endl;
  str.reserve(1000);
  vec.reserve(1000);
  showInfo(str,"String");
  showInfo(vec,"Vector");
  std::cout << std::endl;
  
  std::cout << "Shrinked to the current size: " << std::endl;
  str.shrink_to_fit();
  vec.shrink_to_fit();
  showInfo(str,"String");
  showInfo(vec,"Vector");
  std::cout << std::endl;

}

 

The program is relatively easy to get. That was my first thought. But wait for a second.

To spare typing, I wrote the small function showInfo (lines 7 - 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 resize (lines 49 and 50); you can adjust the capacity of a container with its method reserve (lines 56 and 57).

 

Rainer D 6 P2 540x540Modernes C++ Mentoring

Be part of my mentoring programs:

 

 

 

 

Do you want to stay informed about my mentoring programs: Subscribe via E-Mail.

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's capacity to its size with the method shrink_to_fit (lines 63 and 64).

Before I present the program's output on Linux and Windows, let me make a few observations.

  1. Adjusting the size and capacity of the container is done automatically. I haven't used any memory operations like new and delete.
  2. std::string and std::vector support the same interface. The only exception to this rule is line 41. Here I added a C string to a C++ string.
  3. By using the method cont.resize(n), the container cont will get new default-initialized elements if n > cont.size() is accurate.
  4. By using the method cont.reserve(n), the container cont will be get new memory for at least n elements if n > cont.capacity() is true.
  5. The call shrink_to_fit 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 shrink_to_fit with GCC, clang, or cl.exe always freed the unnecessary memory.

Here is the output of the program.

 

stringAndVectorstringAndVectorWin

My little astonishment

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 std::string. Therefore, the empty std::string has 15 elements. But I was more astonished that the maximum size of a std::string is as big as the maximum size of a std::vector<int> on Linux. This is astonishing because an int is four times as big as a char on Linux and Windows.

#include <iostream>

int main(){
    
  std::cout << std::endl;

  std::cout << "sizeof(char): " << sizeof(char) << std::endl;
  std::cout << "sizeof(int): " << sizeof(int) << std::endl;
  
  std::cout << std::endl;

}

 

sizeofsizeofWin

 

You have to interpret both values as maximum values. Any ideas on the discrepancy?

My astonishment has disappeared

Thanks to the help of Mark Abraham and Clément Gregoire, the riddle is solved.

Microsoft implementation is more greedy

Microsoft Visuals std::string 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.

GCC with conformant std::string implementation

 If I use GCC 5.3 with a conformant std::string implementation, the picture will differ.

 

stringAndVectorGCC5 3

To use the conformant std::string implementation in GCC 5.3,  I must use the compiler flag -D_GLIBCXX_USE_CXX11_ABI=1. Now, the maximum size of std::string is two times that of std::vector<int>. The C++11 standard says about max_size(): "The size of the largest possible string." Now, I'm fine.

What's next?

I will have in the next post a closer look at std::array. std::array combines the best of two worlds. On the one hand, std::array is as lightweight as a C array; on the other hand, std::array supports the same interface as a std::vector.

 

 

 

 

 

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, Animus24, 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, and Rob North.

 

Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, and Slavko Radman.

 

 

My special thanks to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small

 

My special thanks to PVS-Studio PVC Logo

 

My special thanks to Tipi.build tipi.build logo

 

My special thanks to Take Up Code TakeUpCode 450 60

 

Seminars

I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

Bookable (Online)

German

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++

New

  • Clean Code with Modern C++
  • C++20

Contact Me

Modernes C++,

RainerGrimmDunkelBlauSmall

Tags: Memory

Comments   

+1 #1 Pete 2016-12-17 18:13
I may be an idiot but I think that ascii chars are 8 bits which is a byte which is 1 in bytecount and the INT is four bytes. Which is 4.
Quote
+1 #2 Mark Abraham 2016-12-18 05:13
It would be good to report the versions of your compilers. The standard library in sufficiently recent VC implements the small string optimisation (SSO). That makes the minimum size 16 bytes, which the implementation handles differently for different sizes. Small strings have no dynamically allocated memory, which is a useful optimisation. Maybe they can also point to four dynamic allocations, which may explain the four-fold greater size with the VC standard library. However these conveniences make the string-related code more complicated and perhaps slightly slower.
Quote
0 #3 Lectem 2016-12-18 06:23
"the cl.exe compiler is a little bit more greedy. That holds in particular true for std::string" This has nothing to do with cl.exe, it is the MSVC STL implementation. The reason it gives a size of 15 is because it probably uses SSO (small string optimization)
Quote
0 #4 Rainer Grimm 2016-12-18 09:03
Quoting Pete:
I may be an idiot but I think that ascii chars are 8 bits which is a byte which is 1 in bytecount and the INT is four bytes. Which is 4.

Pete, you are right. My reasoning is totally broken. I will adjust it.
Quote
0 #5 neo2 2016-12-21 16:41
Howdy I am so thrilled I found your web site, I really found you by error, while
I was searching on Google for something else, Anyways I am here now and would just like to say
many thanks for a tremendous post and a all round enjoyable blog (I also love the theme/design), I don’t have time to browse
it all at the moment but I have bookmarked it and also added your RSS feeds,
so when I have time I will be back to read much more, Please do keep up
the great jo.
Quote
0 #6 ductless 2017-07-08 00:42
Appreciate this post. Let me try it out.
Quote

Stay Informed about my Mentoring

 

Mentoring

English Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Course: The All-in-One Guide to C++20

Course: Master Software Design Patterns and Architecture in C++

Subscribe to the newsletter (+ pdf bundle)

All tags

Blog archive

Source Code

Visitors

Today 1754

Yesterday 4344

Week 38632

Month 18878

All 12097087

Currently are 138 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments