In addition to the other answers ...
I did extensive tests on this problem a while ago and came to the conclusion that the most effective solution (GCC 4.7 and 4.8 on Linux x86 / x64 / ARM) in all cases of use is primarily reserve() , a result string with enough storage space all concatenated strings, and then only append() them (or use operator +=() , which does not matter).
Unfortunately, it seems to me that I deleted this test, so you only have my word (but you can easily adapt the Mats Petersson test to see for yourself if my word is not enough).
In a nutshell:
const string space = " "; string result; result.reserve(5 + space.size() + 5); result += "hello"; result += space; result += "world";
Depending on the specific use case (number, types and sizes of concatenated strings), sometimes this method is the most effective, and in other cases it is comparable to other methods, but it is never worse.
The problem is that it is actually very difficult to calculate the total required size in advance, especially when mixing string literals and std::string (as the example above shows). The maintainability of such code is absolutely terrible as soon as you modify one of the literals or add another line to concatenate.
One approach would be to use sizeof to calculate the size of literals, but IMHO creates as much mess as it solves, maintainability is still terrible:
#define STR_HELLO "hello" #define STR_WORLD "world" const string space = " "; string result; result.reserve(sizeof(STR_HELLO)-1 + space.size() + sizeof(STR_WORLD)-1); result += STR_HELLO; result += space; result += STR_WORLD;
Useful solution (C ++ 11, variable templates)
Finally, I decided to create a set of variable templates that efficiently deal with calculating the size of strings (for example, the size of string literals is determined at compile time), reserve() as needed, and then combines everything.
Here, hopefully this is useful:
namespace detail { template<typename> struct string_size_impl; template<size_t N> struct string_size_impl<const char[N]> { static constexpr size_t size(const char (&) [N]) { return N - 1; } }; template<size_t N> struct string_size_impl<char[N]> { static size_t size(char (&s) [N]) { return N ? strlen(s) : 0; } }; template<> struct string_size_impl<const char*> { static size_t size(const char* s) { return s ? strlen(s) : 0; } }; template<> struct string_size_impl<char*> { static size_t size(char* s) { return s ? strlen(s) : 0; } }; template<> struct string_size_impl<std::string> { static size_t size(const std::string& s) { return s.size(); } }; template<typename String> size_t string_size(String&& s) { using noref_t = typename std::remove_reference<String>::type; using string_t = typename std::conditional<std::is_array<noref_t>::value, noref_t, typename std::remove_cv<noref_t>::type >::type; return string_size_impl<string_t>::size(s); } template<typename...> struct concatenate_impl; template<typename String> struct concatenate_impl<String> { static size_t size(String&& s) { return string_size(s); } static void concatenate(std::string& result, String&& s) { result += s; } }; template<typename String, typename... Rest> struct concatenate_impl<String, Rest...> { static size_t size(String&& s, Rest&&... rest) { return string_size(s) + concatenate_impl<Rest...>::size(std::forward<Rest>(rest)...); } static void concatenate(std::string& result, String&& s, Rest&&... rest) { result += s; concatenate_impl<Rest...>::concatenate(result, std::forward<Rest>(rest)...); } }; }
The only interesting part about the public interface is the last template<typename... Strings> std::string concatenate(Strings&&... strings) template. The use is simple:
int main() { const string space = " "; std::string result = concatenate("hello", space, "world"); std::cout << result << std::endl; }
When enabling optimizations, any decent compiler should be able to deploy the concatenate call to the same code as my first example, where I manually wrote everything. As for GCC 4.7 and 4.8, the generated code is pretty much identical, as well as performance.