# String concatenation Warning: before you read this, remember the rule #1 we mentioned at the beginning. **Optimize your code only if you can observe a visible overhead with you profiling tools**. Said that... As we said, strings are a little more than vectors of characters, therefore they may need heap allocations to store all their elements. Concatenating strings in C++ is very easy, but there is something we should be aware of. ## "Default" concatenation Look at this familiar line of code. ```C++ std:string big_string = first + " " + second + " " + third; // Where... // std::string first("This is my first string."); // std::string second("This is the second string I want to append."); // std::string third("This is the third and last string to append."); ``` Noticing anything suspicious? Think about heap allocations... ![](img/spider_senses.png) Let me rewrite it like this: ```C++ std:string big_string = (((first + " ") + second) + " ") + third; ``` Hopefully you got it. To concatenate strings of this length, you will need multiple heap allocations and copies from the old memory block to the new one. If only `std::string` had a method similar to `std::vector::reserve()` :( Hey, wait... [what is this](https://en.cppreference.com/w/cpp/string/basic_string/reserve)? ## "Manual" concatenation Let's use reserve to reduce the amount of heap allocations to exactly one. We can calculate the total amount of characters needed by `big_string` in advance and reserve it like this: ```C++ std::string big_one; big_one.reserve(first_str.size() + second_str.size() + third_str.size() + strlen(" ")*2 ); big_one += first; big_one += " "; big_one += second; big_one += " "; big_one += third; ``` I know what you are thinking and you are 100% right. ![](img/feel_bad.jpg) That is a horrible piece of code... that is **2.5 times faster** than the default string concatenation! ## Variadic concatenation Can we create a string concatenation function that is fast, reusable **and** readable? We do, but we need to use some heavy weapons of Modern C++: **variadic templates**. There is a very [nice article about variadic templates here](https://arne-mertz.de/2016/11/more-variadic-templates/), that you should probably read if you are not familiar with them. ```C++ //--- functions to calculate the total size --- size_t StrSize(const char* str) { return strlen(str); } size_t StrSize(const std::string& str) { return str.size(); } template size_t StrSize(const Head& head, Tail const&... tail) { return StrSize(head) + StrSize(tail...); } //--- functions to append strings together --- template void StrAppend(std::string& out, const Head& head) { out += head; } template void StrAppend(std::string& out, const Head& head, Args const&... args) { out += head; StrAppend(out, args...); } //--- Finally, the function to concatenate strings --- template std::string StrCat(Args const&... args) { size_t tot_size = StrSize(args...); std::string out; out.reserve(tot_size); StrAppend(out, args...); return out; } ``` That was a lot of complex code, even for a trained eye. But the good news are that it is very easy to use: ```C++ std:string big_string = StrCat(first, " ", second, " ", third ); ``` So, how fast is that? ![](img/string_concatenation.png) The reason why the version with variadic templates is slightly slower than the "ugly" manual concatenation is... I have no idea! What I **do** know is that it is twice as fast as the default one and it is not an unreadable mess. ## Before you copy and paste my code... My implementation of `StrCat` is very limited and I just wanted to make a point: beware of string concatenations in C++. Nevertheless, don't think it twice and use [{fmt}](https://github.com/fmtlib/fmt) instead. Not only it is an easy to integrate, well documented and **very** fast library to format strings. It is also an implementation of [C++20 std::format](https://en.cppreference.com/w/cpp/utility/format). This means that you can write code that is readable, performant and future proof!