One of the big advantages of C++ string to a C string and of a std::vector to a C array is it that both C++ containers automatically manage their memory. Of course, that holds true for all further containers of the Standard Template Library. In this post, I will have a closer look at the automatic memory management of std::vector and std::string.
From the user 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 most important 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 quite easy to get. That was my first thought. But wait a second.
To spare typing I wrote the small function showInfo (line 7 - 13). This function returns for a container its size (line 10) and its capacity (line 11). The size of a container is its number of elements, 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 (line 49 and 50); you can adjust the capacity of a container with its method reserve (line 56 and 57).
But, back to the program from top to bottom. I create in line 19 and 20 an empty string and an empty vector. Afterwards, the program displays the maximum numbers of elements a string or vector can have. After each operation on both container, it returns their size and capacity. That holds true for the initialization of the containers (line 34 and 35), for the addition of four new elements (line 42 and 43), the resizing of the containers to 30 elements (line 49 and 50) and the reserving of additional memory for at least 1000 elements (line 56 and 57). With C++11, you can shrink with the method shrink_to_fit (line 63 and 64) the container's capacity to its size.
Before I present the output of the program on Linux and Windows let me make a few observations.
- The adjustment of the size and the capacity of the container is done automatically. I haven't used any kind of memory operations like new and delete.
- 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.
- By using the method cont.resize(n) the container cont will get new default-initialized elements, if n > cont.size() is true.
- 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.
- The call shrink_to_fit is non-binding. That means the C++ runtime has not 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.


My little astonishment
The program shows, that the MSVC 15 STL implementation is a little bit 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 by the fact 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 a 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;
}


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.
If I use a GCC 5.3 with a conformant std::string implementation, the picture will be different.

To use the conformant std::string implementation in GCC 5.3, I have to use the compiler flag -D_GLIBCXX_USE_CXX11_ABI=1.Now, the maximum size of std::string is two times the maximum size 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 from two worlds. On 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, and Ann Shatoff.
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 
My special thanks to PVS-Studio 
My special thanks to Tipi.build 
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
- Phone: +49 7472 917441
- Mobil:: +49 176 5506 5086
- Mail: This email address is being protected from spambots. You need JavaScript enabled to view it.
- German Seminar Page: www.ModernesCpp.de
- Mentoring Page: www.ModernesCpp.org
Modernes C++,

Comments
Pete, you are right. My reasoning is totally broken. I will adjust it.
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.
RSS feed for comments to this post