4

Say I have this simple function

void foo(string a, string b) {

  std::string a_string = a + a; 
  // reassign a new string to a_string
  a_string = b + b + b;

  // more stuff
}

Does the memory reserved for a+a get released as soon as a_string is assigned a new string?

Newbie in C++ memory management. I'm still wrapping my head around it.

Curious Learner
  • 343
  • 2
  • 9
  • 1
    Depends on the size of the strings. E.g. if both are equal size, the same memory will probably get over written, however if the second is larger, a realloc may take place and in that case, yes the old memory is released. There is also something called the "Small string optimization" you might be interested in. – nitronoid Mar 28 '19 at 02:52

5 Answers5

2

It depends if it is a short or long string:

std::string a_string = a + a;
// reassign a new string to a_string
a_string = b + b + b; 

First, a+a is constructed directly as a_string due to guaranteed copy elison (c++17). No freeing is going on here.

Then, if a_string is short enough it is allocated on stack, without additional heap allocations. This Short String Optimization (SSO) is performed by most compilers, but is not mandated by the standard.

If SSO took place, then this does not free any space in a_string but merely reuses it. The memory goes nowhere:

a_string = b + b + b; 

However, if a_string is too long for SSO, then this line does free heap space allocated for the string.

It is clear to see where memory goes when the declaration of std::string is examined:

template< 
   class CharT,
   class Traits = std::char_traits<CharT>,
   class Allocator = std::allocator<CharT>
> class basic_string;

The memory of the non-SSO string is allocated and freed with std::allocator. This allocator allocates and frees memory with the new and delete operaors. Usually they use malloc/free behind the scenes. This is how malloc and free work.

It is easy to find out how big as SSO string can be by running

std::cout << std::string().capacity() << '\n';

For clang 8.0.0 on 64 bit Intel SSO is for strings up to 22 chars, and for gcc 8.3 it is only 15 chars.

Michael Veksler
  • 8,217
  • 1
  • 20
  • 33
1

From what I know the string is just copied to memory allocated for a_string since it is more efficient than freeing memory and allocating new one. If the memory allocated for (a+a) is less than size allocated for a_string it gets resized.

String manages the memory for you. You do not have to ever allocate buffer space when you add or remove data to the string. If you add more than will fit in the currently-allocated buffer, string will reallocate it for you behind the scenes.

std::string and its automatic memory resizing

Nevus
  • 1,307
  • 1
  • 9
  • 21
  • Thanks for the answer. The intention of the question wasn't to decide whether to allocate memory. It is simply so that I can understand what goes on behind the scene. – Curious Learner Mar 28 '19 at 04:11
1

std::string is a ressource manager class. It owns the underlying char*. The allocated memory gets deleted as soon as the destructor of the std::string object is called, i.e. when the object itself goes out of scope.

The same thing happens when std::string is reassigned. The old memory will be freed if it's to small for the new string and potentially replaced with new heap memory. Ressource Management classes such as std::string have a strong guarantee to never leak memory (assuming standard conforming implementation).

Because you are assigning a temporary, no copy (and thus no reallocation) needs to take place. Instead, the contents of the temporary b + b + b will me moved into the string. This means copying the underlying pointer of the temporary into the existing string object and stripping the temporary of the ownership of that pointer. This means, that the temporary no longer owns the memory and thus will not delete it when its destructor is called directly after the assignment. This has the tremendous advantage, that only a pointer needs to be copied instead of a memcpy of the complete string.

Other ressource management classes with that guarantee include smart pointers (std::unique_pointer, std::shared_pointer) and collections (e.g. std::vector, std::list, std::map...).

In modem C++ it's rarely necessary to do this kind of memory management manually. The mentioned ressource management classes cover most cases and should be preferred over manual memory management nearly all of the time unless it's really necessary and you know exactly what you are doing.

LukeG
  • 638
  • 10
  • 20
0

No, a string works a bit like a vector in C++ in that once the space is reserved in memory, it will not be released unless explicitly told to do so, or it passes its max capacity. This is to avoid resizing as much as possible, because doing so would mean allocating a new array of characters, copying over the necessary values, and deleting the old array. By maintaining the reserved memory, removing a character doesn't require making a brand new array, and the reallocation only needs to happen when the string isn't large enough to contain what you're trying to put in it. Hope that helps!

EnigmaticBacon
  • 353
  • 6
  • 21
0

Notice than you have a lot of allocations, starting with arguments passed by value instead of by const reference.

Then a+a that you cannot really avoid.

then the interesting part:

(b + b) + b which create 2 allocations for the 2 temporaries.

then you use the move assignment which replace a_string by the temporary: No allocation.

Jarod42
  • 203,559
  • 14
  • 181
  • 302