December 7, 2020

Constant string and reference C++

Do you know why the “const std::string&” declaration is recommended? This is a classic one and one of the rare recommendations which mix performance and readability.

How works std::string

C++ - String declaration

std::string my_string = “HELLO”;

The behavior of a std::string looks simple! This is an object which points to the heap. For example, when I declare a simple std::string into the heap, my memory will look like this:


As you see, a new variable is created in the stack. This simple variable contains data like the size of the content, and the pointer to the content. Even if it looks easy to use, sometimes, a simple string can cause trouble. It is a perfect entry to introduce some issues about "const declaration"!

What happens when I use a const std::string in a function?

C++ - Const string without reference

void my_function(const std::string my_string_in_param)
{
MY_FUNCTION_IMPL;
}
 
int main()
{
std::string my_string;
function(my_string);
return 0;
}

Here two instructions:

The “const” declares that the variable is not altered by the program. Then, we have a string that cannot be modified.

However, there is an issue here. Your compiler does not optimize the “const” variable. Indeed, another thread could modify your variable and alter the behavior of your function. Then, you have a memory which looks like this:


Const is a great feature to certify to developers that a variable is not modified in a function. However, as you see, the value is copied in the stack. This kind of behavior is under-optimized and allocate in the stack a memory which is not modified. Fortunately, you can easily resolve this!

How to avoid this copy: The reference.

C++ - Const string with reference

void my_function(const std::string &my_string_in_param)
{
MY_FUNCTION_IMPL;
}
 
int main()
{
std::string my_string;
function(my_string);
return 0;
}

Note the only difference here. This is the symbol "&" in my parameter list. Thanks to this symbol, I declare now that "my_string_in_param" is passed by reference!
By using a reference, you are giving to your function the address of your parameter. You will see that my behavior in memory is simpler:


This address will point to the string contained in your stack. Thanks to the "const" plus "reference" instruction, you optimize the usage of your code AND notify other developers that your string is not modified!

To go further with “const”…

Perfect, your function is now optimized:

  • No copy.
  • No allocation in the heap.
  • Quick behavior.
  • Inform developers that the variable is not altered..

However, we  combined “const” with “reference” syntax. This is named the “const reference”.

As you see, even if “const” is a simple concept in C++, this syntax is messing in multiple situations. The compiler does not systematically optimize "const" declarations. The “const reference” is only the visible part.

Another tricky case is the usage of constant method:

  • By declaring const, your compiler ensures that your private variables are not altered.
  • However, in multi-threading context, a “mutex” is regularly used (acquire and release… Even in RAII).

To unblock this situation, another syntax: “The Mutable”.

Do not hesitate to review https://isocpp.org/wiki/faq/const-correctness to get more information about the "const" usages!

About the author 

Axel Fortun

​Developer specialized in Linux environment and embedded systems.
​Knowledge in multiple languages as C/C++, Java, Python​ and AngularJs.
​Working as Software developer since 2014 with a beginning in the car industry​ and then in ​medical systems.