C++ 字符串中最优化的连接方式

C++ 字符串中最优化的连接方式,c++,string,concatenation,C++,String,Concatenation,我们每天都会遇到很多情况,我们必须在代码中执行繁琐的字符串操作。我们都知道字符串操作是昂贵的操作。我想知道现有版本中哪一个最便宜 最常见的操作是串联(这在某种程度上是我们可以控制的)。连接STD最好的方法是:C++中的字符串和各种处理方法来加快级联? 我是说 std::string l_czTempStr; 1).l_czTempStr = "Test data1" + "Test data2" + "Test data3"; 2). l_czTempStr = "Test data1";

我们每天都会遇到很多情况,我们必须在代码中执行繁琐的字符串操作。我们都知道字符串操作是昂贵的操作。我想知道现有版本中哪一个最便宜

最常见的操作是串联(这在某种程度上是我们可以控制的)。连接STD最好的方法是:C++中的字符串和各种处理方法来加快级联?

我是说

std::string l_czTempStr;

1).l_czTempStr = "Test data1" + "Test data2" + "Test data3";

2). l_czTempStr =  "Test data1"; 
    l_czTempStr += "Test data2";
    l_czTempStr += "Test data3";

3). using << operator

4). using append()
std::string l_czTempStr;
1) .l_czTempStr=“测试数据1”+“测试数据2”+“测试数据3”;
2). l_czTempStr=“测试数据1”;
l_czTempStr+=“测试数据2”;
l_czTempStr+=“测试数据3”;

3). 使用这里有一个小测试套件:

#include <iostream>
#include <string>
#include <chrono>
#include <sstream>

int main ()
{
    typedef std::chrono::high_resolution_clock clock;
    typedef std::chrono::duration<float, std::milli> mil;
    std::string l_czTempStr;
    std::string s1="Test data1";
    auto t0 = clock::now();
    #if VER==1
    for (int i = 0; i < 100000; ++i)
    {
        l_czTempStr = s1 + "Test data2" + "Test data3";
    }
    #elif VER==2
    for (int i = 0; i < 100000; ++i)
    {
        l_czTempStr =  "Test data1"; 
        l_czTempStr += "Test data2";
        l_czTempStr += "Test data3";
    }
    #elif VER==3
    for (int i = 0; i < 100000; ++i)
    {
        l_czTempStr =  "Test data1"; 
        l_czTempStr.append("Test data2");
        l_czTempStr.append("Test data3");
    }
    #elif VER==4
    for (int i = 0; i < 100000; ++i)
    {
        std::ostringstream oss;
        oss << "Test data1";
        oss << "Test data2";
        oss << "Test data3";
        l_czTempStr = oss.str();
    }
    #endif
    auto t1 = clock::now();
    std::cout << l_czTempStr << '\n';
    std::cout << mil(t1-t0).count() << "ms\n";
}
#包括
#包括
#包括
#包括
int main()
{
typedef std::chrono::高分辨率时钟;
类型定义标准::时间::持续时间密耳;
std::字符串l_czTempStr;
std::string s1=“测试数据1”;
自动t0=时钟::现在();
#如果VER==1
对于(int i=0;i<100000;++i)
{
l_czTempStr=s1+“测试数据2”+“测试数据3”;
}
#elif VER==2
对于(int i=0;i<100000;++i)
{
l_czTempStr=“测试数据1”;
l_czTempStr+=“测试数据2”;
l_czTempStr+=“测试数据3”;
}
#elif VER==3
对于(int i=0;i<100000;++i)
{
l_czTempStr=“测试数据1”;
l_czTempStr.追加(“测试数据2”);
l_czTempStr.追加(“测试数据3”);
}
#elif VER==4
对于(int i=0;i<100000;++i)
{
std::ostringstream oss;

oss最糟糕的情况是使用普通的旧的
strcat
(或
sprintf
),因为
strcat
需要一个C字符串,并且必须“计数”对于长字符串来说,这是一个真正的性能受累者。C++风格字符串要好得多,性能问题可能是内存分配,而不是计算长度。但是,字符串再次几何增长(每次需要增长一倍),所以它并不可怕。 我非常怀疑上述所有方法最终都具有相同或至少非常相似的性能。如果有什么不同的话,我希望
stringstream
会更慢,因为它在支持格式方面的开销很大,但我也怀疑它是微不足道的

因为这类事情很“有趣”,我会带着一个基准回来

编辑:

注意,这些结果适用于运行X8664 Linux的机器,用G+4.4.3编译。其他OS、编译器和C++运行库实现可能会有所不同。如果性能对应用程序很重要,那么使用您所使用的编译器对系统来说,关键是对系统的使用。 下面是我为测试这一点而编写的代码。它可能不是真实场景的完美表示,但我认为它是一个具有代表性的场景:

#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <cstring>

using namespace std;

static __inline__ unsigned long long rdtsc(void)
{
    unsigned hi, lo;
    __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
    return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
}

string build_string_1(const string &a, const string &b, const string &c)
{
    string out = a + b + c;
    return out;
}

string build_string_1a(const string &a, const string &b, const string &c)
{
    string out;
    out.resize(a.length()*3);
    out = a + b + c;
    return out;
}

string build_string_2(const string &a, const string &b, const string &c)
{
    string out = a;
    out += b;
    out += c;
    return out;
}

string build_string_3(const string &a, const string &b, const string &c)
{
    string out;
    out = a;
    out.append(b);
    out.append(c);
    return out;
}


string build_string_4(const string &a, const string &b, const string &c)
{
    stringstream ss;

    ss << a << b << c;
    return ss.str();
}


char *build_string_5(const char *a, const char *b, const char *c)
{
    char* out = new char[strlen(a) * 3+1];
    strcpy(out, a);
    strcat(out, b);
    strcat(out, c);
    return out;
}



template<typename T>
size_t len(T s)
{
    return s.length();
}

template<>
size_t len(char *s)
{
    return strlen(s);
}

template<>
size_t len(const char *s)
{
    return strlen(s);
}



void result(const char *name, unsigned long long t, const string& out)
{
    cout << left << setw(22) << name << " time:" << right << setw(10) <<  t;
    cout << "   (per character: " 
         << fixed << right << setw(8) << setprecision(2) << (double)t / len(out) << ")" << endl;
}

template<typename T>
void benchmark(const char name[], T (Func)(const T& a, const T& b, const T& c), const char *strings[])
{
    unsigned long long t;

    const T s1 = strings[0];
    const T s2 = strings[1];
    const T s3 = strings[2];
    t = rdtsc();
    T out = Func(s1, s2, s3);
    t = rdtsc() - t; 

    if (len(out) != len(s1) + len(s2) + len(s3))
    {
        cout << "Error: out is different length from inputs" << endl;
        cout << "Got `" << out << "` from `" << s1 << "` + `" << s2 << "` + `" << s3 << "`";
    }
    result(name, t, out);
}


void benchmark(const char name[], char* (Func)(const char* a, const char* b, const char* c), 
               const char *strings[])
{
    unsigned long long t;

    const char* s1 = strings[0];
    const char* s2 = strings[1];
    const char* s3 = strings[2];
    t = rdtsc();
    char *out = Func(s1, s2, s3);
    t = rdtsc() - t; 

    if (len(out) != len(s1) + len(s2) + len(s3))
    {
        cout << "Error: out is different length from inputs" << endl;
        cout << "Got `" << out << "` from `" << s1 << "` + `" << s2 << "` + `" << s3 << "`";
    }
    result(name, t, out);
    delete [] out;
}


#define BM(func, size) benchmark(#func " " #size, func, strings ## _ ## size)


#define BM_LOT(size) BM(build_string_1, size); \
    BM(build_string_1a, size); \
    BM(build_string_2, size); \
    BM(build_string_3, size); \
    BM(build_string_4, size); \
    BM(build_string_5, size);

int main()
{
    const char *strings_small[]  = { "Abc", "Def", "Ghi" };
    const char *strings_medium[] = { "abcdefghijklmnopqrstuvwxyz", 
                                     "defghijklmnopqrstuvwxyzabc", 
                                     "ghijklmnopqrstuvwxyzabcdef" };
    const char *strings_large[]   = 
        { "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
          "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
          "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
          "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
          "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
          "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
          "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
          "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
          "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
          "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", 

          "defghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc" 
          "defghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc" 
          "defghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc" 
          "defghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc" 
          "defghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc"

          "defghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc" 
          "defghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc" 
          "defghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc" 
          "defghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc" 
          "defghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabc", 

          "ghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef"
          "ghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef"
          "ghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef"
          "ghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef"
          "ghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef"
          "ghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef"
          "ghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef"
          "ghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef"
          "ghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef"
          "ghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef"
        };

    for(int i = 0; i < 5; i++)
    {
        BM_LOT(small);
        BM_LOT(medium);
        BM_LOT(large);
        cout << "---------------------------------------------" << endl;
    }
}
相同的代码,以32位运行:

build_string_1 small   time:      4289   (per character:   476.56)
build_string_1a small  time:      5967   (per character:   663.00)
build_string_2 small   time:      3329   (per character:   369.89)
build_string_3 small   time:      3047   (per character:   338.56)
build_string_4 small   time:     22018   (per character:  2446.44)
build_string_5 small   time:      3026   (per character:   336.22)
build_string_1 medium  time:      4089   (per character:    52.42)
build_string_1a medium time:      8075   (per character:   103.53)
build_string_2 medium  time:      4569   (per character:    58.58)
build_string_3 medium  time:      4326   (per character:    55.46)
build_string_4 medium  time:     22751   (per character:   291.68)
build_string_5 medium  time:      2252   (per character:    28.87)
build_string_1 large   time:      8695   (per character:     3.72)
build_string_1a large  time:     12818   (per character:     5.48)
build_string_2 large   time:      8202   (per character:     3.51)
build_string_3 large   time:      8351   (per character:     3.57)
build_string_4 large   time:     38250   (per character:    16.35)
build_string_5 large   time:      8143   (per character:     3.48)
由此,我们可以得出以下结论:

  • 最好的选择是一次追加一位(
    out.append()
    out+=
    ),而“链式”方法相当接近

  • 预先分配字符串没有帮助

  • 使用
    stringstream
    是一个非常糟糕的主意(速度慢2-4倍)

  • char*
    使用
    newchar[]
    。在调用函数中使用局部变量使其速度最快,但比较起来有点不公平

  • 在组合短字符串时会有相当大的开销-仅复制数据最多应为每个字节一个周期[除非数据不适合缓存]

  • edit2

    根据评论添加:

    string build_string_1b(const string &a, const string &b, const string &c)
    {
        return a + b + c;
    }
    

    结果如下:

    build_string_1 small   time:      4075   (per character:   452.78)
    build_string_1a small  time:      5384   (per character:   598.22)
    build_string_2 small   time:      2669   (per character:   296.56)
    build_string_3 small   time:      2427   (per character:   269.67)
    build_string_4 small   time:     19380   (per character:  2153.33)
    build_string_5 small   time:      6299   (per character:   699.89)
    build_string_1 medium  time:      3983   (per character:    51.06)
    build_string_1a medium time:      6970   (per character:    89.36)
    build_string_2 medium  time:      4072   (per character:    52.21)
    build_string_3 medium  time:      4000   (per character:    51.28)
    build_string_4 medium  time:     19614   (per character:   251.46)
    build_string_5 medium  time:      6304   (per character:    80.82)
    build_string_1 large   time:      8491   (per character:     3.63)
    build_string_1a large  time:      9563   (per character:     4.09)
    build_string_2 large   time:      6154   (per character:     2.63)
    build_string_3 large   time:      5992   (per character:     2.56)
    build_string_4 large   time:     32450   (per character:    13.87)
    build_string_5 large   time:     15768   (per character:     6.74)
    
    build_string_1 small   time:      3845   (per character:   427.22)
    build_string_1b small  time:      3165   (per character:   351.67)
    build_string_2 small   time:      3176   (per character:   352.89)
    build_string_2a small  time:      1904   (per character:   211.56)
    
    build_string_1 large   time:      9056   (per character:     3.87)
    build_string_1b large  time:      6414   (per character:     2.74)
    build_string_2 large   time:      6417   (per character:     2.74)
    build_string_2a large  time:      4179   (per character:     1.79)
    
    /*
    
    g++ "qtcreator debug mode"
    ----------------String Comparison---------------- 
    
    -------------------------string, plain addition-------------------
    Test data1Test data2Test data3
    11.8496ms
    ---------------------------------------------------------------------------
    
    -------------------------string, incremental-------------------
    Test data1Test data2Test data3
    3.55597ms
    ---------------------------------------------------------------------------
    
    -------------------------string, append-------------------
    Test data1Test data2Test data3
    3.53099ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, creation in each loop, incremental-------------------
    Test data1Test data2Test data3
    58.1577ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, 1 creation, incremental-------------------
    Test data1Test data2Test data3
    11.1069ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, 1 creation, plain addition-------------------
    Test data1Test data2Test data3
    10.9946ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, 1 creation, clearing calling inline function, plain addition-------------------
    Test data1Test data2Test data3
    10.9502ms
    ---------------------------------------------------------------------------
    
    -------------------------string, creation in each loop-------------------
    Test data1Test data2Test data3
    9.97495ms
    ---------------------------------------------------------------------------
    
    
    g++ "qtcreator release mode" (optimized)
    ----------------String Comparison----------------
    
    -------------------------string, plain addition-------------------
    Test data1Test data2Test data3
    8.41622ms
    ---------------------------------------------------------------------------
    
    -------------------------string, incremental-------------------
    Test data1Test data2Test data3
    2.55462ms
    ---------------------------------------------------------------------------
    
    -------------------------string, append-------------------
    Test data1Test data2Test data3
    2.5154ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, creation in each loop, incremental-------------------
    Test data1Test data2Test data3
    54.3232ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, 1 creation, incremental-------------------
    Test data1Test data2Test data3
    8.71854ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, 1 creation, plain addition-------------------
    Test data1Test data2Test data3
    8.80526ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, 1 creation, clearing calling inline function, plain addition-------------------
    Test data1Test data2Test data3
    8.78186ms
    ---------------------------------------------------------------------------
    
    -------------------------string, creation in each loop-------------------
    Test data1Test data2Test data3
    8.4034ms
    ---------------------------------------------------------------------------
    */
    

    (32位运行,但64位显示的结果非常相似)。

    与大多数微观优化一样,您需要测量每个选项的效果,首先通过测量确定这确实是一个值得优化的瓶颈。没有明确的答案

    append
    +=
    应该做完全相同的事情

    +
    在概念上效率较低,因为您正在创建和销毁临时文件。您的编译器可能会或可能无法将其优化为与追加一样快

    使用总大小调用
    reserve
    可能会减少所需的内存分配数量-它们可能是最大的瓶颈


    除了其他答案之外

    不久前,我对这个问题做了大量的基准测试,并得出结论:在所有用例中,最有效的解决方案(Linux x86/x64/ARM上的GCC 4.7和4.8)是首先
    reserve()
    结果字符串,该字符串有足够的空间容纳所有连接的字符串,然后只
    append()
    它们(或者使用
    操作符+=()
    ,这没有什么区别)

    不幸的是,我似乎删除了那个基准,所以你只有我的话(但如果我的话不够的话,你可以很容易地修改Mats Peterson的基准来自己验证这一点)

    简言之:

    const string space = " ";
    string result;
    result.reserve(5 + space.size() + 5);
    result += "hello";
    result += space;
    result += "world";
    

    根据确切的用例(连接字符串的数量、类型和大小),有时这种方法是最有效的,而其他时候它与其他方法是一致的,但它永远不会更糟。


    问题是,提前计算所需的总大小确实很痛苦,特别是在混合字符串文本和
    std::string
    时(我相信上面的例子在这方面已经足够清楚了)。一旦您修改一个文本或添加另一个要连接的字符串,此类代码的可维护性就绝对糟糕

    一种方法是使用
    sizeof
    来计算文本的大小,但不管它造成的混乱程度如何,它的可维护性仍然很糟糕:

    #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;
    
    可用的解决方案(C++11,可变模板) 我最终
    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)...);
        }
      };
    
    } // namespace detail
    
    template<typename... Strings>
    std::string concatenate(Strings&&... strings) {
      std::string result;
      result.reserve(detail::concatenate_impl<Strings...>::size(std::forward<Strings>(strings)...));
      detail::concatenate_impl<Strings...>::concatenate(result, std::forward<Strings>(strings)...);
      return result;
    }
    
    int main() {
      const string space = " ";
      std::string result = concatenate("hello", space, "world");
      std::cout << result << std::endl;
    }
    
    #include <iostream>
    #include <string>
    #include <chrono>
    #include <sstream>
    #include <functional>
    
    
    template <typename F> void time_measurement(F f, const std::string& comment)
    {
        typedef std::chrono::high_resolution_clock clock;
        typedef std::chrono::duration<float, std::milli> mil;
        std::string r;
        auto t0 = clock::now();
        f(r);
        auto t1 = clock::now();
        std::cout << "\n-------------------------" << comment << "-------------------\n" <<r << '\n';
        std::cout << mil(t1-t0).count() << "ms\n";
        std::cout << "---------------------------------------------------------------------------\n";
    
    }
    
    inline void clear(std::ostringstream& x)
    {
        x.str("");
        x.clear();
    }
    
    void test()
    {
        std:: cout << std::endl << "----------------String Comparison---------------- " << std::endl;
        const int n=100000;
        {
            auto f=[](std::string& l_czTempStr)
            {
                std::string s1="Test data1";
                for (int i = 0; i < n; ++i)
                {
                    l_czTempStr = s1 + "Test data2" + "Test data3";
                }
            };
            time_measurement(f, "string, plain addition");
       }
    
       {
            auto f=[](std::string& l_czTempStr)
            {
                for (int i = 0; i < n; ++i)
                {
                    l_czTempStr =  "Test data1";
                    l_czTempStr += "Test data2";
                    l_czTempStr += "Test data3";
                }
            };
            time_measurement(f, "string, incremental");
        }
    
        {
             auto f=[](std::string& l_czTempStr)
             {
                for (int i = 0; i < n; ++i)
                {
                    l_czTempStr =  "Test data1";
                    l_czTempStr.append("Test data2");
                    l_czTempStr.append("Test data3");
                }
             };
             time_measurement(f, "string, append");
         }
    
        {
             auto f=[](std::string& l_czTempStr)
             {
                for (int i = 0; i < n; ++i)
                {
                    std::ostringstream oss;
                    oss << "Test data1";
                    oss << "Test data2";
                    oss << "Test data3";
                    l_czTempStr = oss.str();
                }
             };
             time_measurement(f, "oss, creation in each loop, incremental");
         }
    
        {
             auto f=[](std::string& l_czTempStr)
             {
                std::ostringstream oss;
                for (int i = 0; i < n; ++i)
                {
                    oss.str("");
                    oss.clear();
                    oss << "Test data1";
                    oss << "Test data2";
                    oss << "Test data3";
                }
                l_czTempStr = oss.str();
             };
             time_measurement(f, "oss, 1 creation, incremental");
         }
    
        {
             auto f=[](std::string& l_czTempStr)
             {
                std::ostringstream oss;
                for (int i = 0; i < n; ++i)
                {
                    oss.str("");
                    oss.clear();
                    oss << "Test data1" << "Test data2" << "Test data3";
                }
                l_czTempStr = oss.str();
             };
             time_measurement(f, "oss, 1 creation, plain addition");
         }
    
        {
             auto f=[](std::string& l_czTempStr)
             {
                std::ostringstream oss;
                for (int i = 0; i < n; ++i)
                {
                    clear(oss);
                    oss << "Test data1" << "Test data2" << "Test data3";
                }
                l_czTempStr = oss.str();
             };
             time_measurement(f, "oss, 1 creation, clearing calling inline function, plain addition");
         }
    
    
        {
             auto f=[](std::string& l_czTempStr)
             {
                for (int i = 0; i < n; ++i)
                {
                    std::string x;
                    x =  "Test data1";
                    x.append("Test data2");
                    x.append("Test data3");
                    l_czTempStr=x;
                }
             };
             time_measurement(f, "string, creation in each loop");
         }
    
    }
    
    /*
    
    g++ "qtcreator debug mode"
    ----------------String Comparison---------------- 
    
    -------------------------string, plain addition-------------------
    Test data1Test data2Test data3
    11.8496ms
    ---------------------------------------------------------------------------
    
    -------------------------string, incremental-------------------
    Test data1Test data2Test data3
    3.55597ms
    ---------------------------------------------------------------------------
    
    -------------------------string, append-------------------
    Test data1Test data2Test data3
    3.53099ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, creation in each loop, incremental-------------------
    Test data1Test data2Test data3
    58.1577ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, 1 creation, incremental-------------------
    Test data1Test data2Test data3
    11.1069ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, 1 creation, plain addition-------------------
    Test data1Test data2Test data3
    10.9946ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, 1 creation, clearing calling inline function, plain addition-------------------
    Test data1Test data2Test data3
    10.9502ms
    ---------------------------------------------------------------------------
    
    -------------------------string, creation in each loop-------------------
    Test data1Test data2Test data3
    9.97495ms
    ---------------------------------------------------------------------------
    
    
    g++ "qtcreator release mode" (optimized)
    ----------------String Comparison----------------
    
    -------------------------string, plain addition-------------------
    Test data1Test data2Test data3
    8.41622ms
    ---------------------------------------------------------------------------
    
    -------------------------string, incremental-------------------
    Test data1Test data2Test data3
    2.55462ms
    ---------------------------------------------------------------------------
    
    -------------------------string, append-------------------
    Test data1Test data2Test data3
    2.5154ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, creation in each loop, incremental-------------------
    Test data1Test data2Test data3
    54.3232ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, 1 creation, incremental-------------------
    Test data1Test data2Test data3
    8.71854ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, 1 creation, plain addition-------------------
    Test data1Test data2Test data3
    8.80526ms
    ---------------------------------------------------------------------------
    
    -------------------------oss, 1 creation, clearing calling inline function, plain addition-------------------
    Test data1Test data2Test data3
    8.78186ms
    ---------------------------------------------------------------------------
    
    -------------------------string, creation in each loop-------------------
    Test data1Test data2Test data3
    8.4034ms
    ---------------------------------------------------------------------------
    */
    
    #include <iostream>
    #include <string>
    #include <chrono>
    #include <sstream>
    #include <vector>
    #include <cstring>
    
    
    #if VER==TEMPLATE
    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)...);
        }
      };
    
    } // namespace detail
    
    template<typename... Strings>
    std::string concatenate(Strings&&... strings) {
      std::string result;
      result.reserve(detail::concatenate_impl<Strings...>::size(std::forward<Strings>(strings)...));
      detail::concatenate_impl<Strings...>::concatenate(result, std::forward<Strings>(strings)...);
      return result;
    }
    
    #endif
    
    int main ()
    {
    typedef std::chrono::high_resolution_clock clock;
    typedef std::chrono::duration<float, std::milli> ms;
    std::string l_czTempStr;
    
    
    std::string s1="Test data1";
    
    
    auto t0 = clock::now();
    #if VER==PLUS
    for (int i = 0; i < 100000; ++i)
    {
        l_czTempStr = s1 + "Test data2" + "Test data3";
    }
    #elif VER==PLUS_EQ
    for (int i = 0; i < 100000; ++i)
    {
        l_czTempStr =  "Test data1"; 
        l_czTempStr += "Test data2";
        l_czTempStr += "Test data3";
    }
    #elif VER==APPEND
    for (int i = 0; i < 100000; ++i)
    {
        l_czTempStr =  "Test data1"; 
        l_czTempStr.append("Test data2");
        l_czTempStr.append("Test data3");
    }
    #elif VER==STRSTREAM
    for (int i = 0; i < 100000; ++i)
    {
        std::ostringstream oss;
        oss << "Test data1";
        oss << "Test data2";
        oss << "Test data3";
        l_czTempStr = oss.str();
    }
    #elif VER=TEMPLATE
    for (int i = 0; i < 100000; ++i)
    {
        l_czTempStr = concatenate(s1, "Test data2", "Test data3");
    }
    #endif
    
    #define STR_(x) #x
    #define STR(x) STR_(x)
    
    auto t1 = clock::now();
    //std::cout << l_czTempStr << '\n';
    std::cout << STR(VER) ": " << ms(t1-t0).count() << "ms\n";
    }
    
    for ARGTYPE in PLUS PLUS_EQ APPEND STRSTREAM TEMPLATE; do for i in `seq 4` ; do clang++ -std=c++11 -O3 -DVER=$ARGTYPE -Wall -pthread -pedantic main.cpp && ./a.out ; rm ./a.out ; done; done
    
    PLUS       23.5792   
    PLUS       23.3812   
    PLUS       35.1806   
    PLUS       15.9394   24.5201
    PLUS_EQ    15.737    
    PLUS_EQ    15.3353   
    PLUS_EQ    10.7764   
    PLUS_EQ    25.245    16.773425
    APPEND     22.954    
    APPEND     16.9031   
    APPEND     10.336    
    APPEND     19.1348   17.331975
    STRSTREAM  10.2063   
    STRSTREAM  10.7765   
    STRSTREAM  13.262    
    STRSTREAM  22.3557   14.150125
    TEMPLATE   16.6531   
    TEMPLATE   16.629    
    TEMPLATE   22.1885   
    TEMPLATE   16.9288   18.09985