是否简单但经常使用std :: stringstream过早的悲观化?

时间:2014-10-20 20:22:45

标签: c++ performance c++11 stl

我有一个简单的场景。我需要将两个C字符串连接成一个std::string。我决定以两种方式之一做到这一点:

解决方案1 ​​

void ProcessEvent(char const* pName) {
   std::string fullName;
   fullName.reserve(50); // Ensure minimal reallocations for small event names (50 is an arbitrary limit).
   fullName += "com.domain.events.";
   fullName += pName;

   // Use fullName as needed
}

解决方案2

void ProcessEvent(char const* pName) {
   std::ostringstream ss;
   ss << "com.domain.events." << pName;

   std::string fullName{ss.str()};
   // Use fullName as needed
}

我更喜欢解决方案2,因为代码更自然。解决方案1似乎是对性能测试中可测量瓶颈的响应。但是,解决方案1的存在有两个原因:

  1. 减少分配是一项轻微的优化。此应用程序中的事件管理经常使用,因此可能会有好处(但没有进行任何测量)。
  2. 我听说过有关STL流WRT性能的批评。有人建议在进行重字符串构建时仅使用stringstream,特别是那些涉及数字转换和/或操纵器使用的字符串流。
  3. 为了简单起见,优先考虑解决方案2是否过早的悲观化?或者选择解决方案1是否为过早的优化?我想知道我是否过于担心STL流。

2 个答案:

答案 0 :(得分:11)

让我们测量它

使用以下功能进行快速测试:

void func1(const char* text) {
    std::string s;
    s.reserve(50);
    s += "com.domain.event.";
    s += text;
}

void func2(const char* text) {
    std::ostringstream oss;
    oss << "com.domain.event." << text;
    std::string s = oss.str();
}

循环运行每100 000次,在我的计算机上平均得到以下结果(使用gcc-4.9.1):

  

func1:37毫秒

     

func2:87毫秒

也就是说,func1的速度是原来的两倍多。

话虽这么说,我建议使用最清晰,最易读的语法,直到你真的需要这个性能。首先实现可测试程序,然后优化它是否太慢。

修改

正如@Ken P所建议的那样:

void func3(const char* text) {
    std::string s = "com.domain.event" + std::string{text};
}
  

func3:27毫秒

最简单的解决方案往往是最快的。

答案 1 :(得分:0)

你没有提到在字符串中没有预先分配任何东西的第三种选择,只是让优化器做他们最擅长的事情。

鉴于这两项功能,func1func3

void func1(const char* text) {
    std::string s;
    s.reserve(50);
    s += "com.domain.event.";
    s += text;
    std::cout << s;
}

void func3(const char* text) {
    std::string s;
    s += "com.domain.event.";
    s += text;
    std::cout << s;
}

http://goo.gl/m8h2Ks的示例中可以看出,func1的gcc程序集仅用于为50个字符保留空间将比func3中没有预分配时添加额外的3个指令。其中一个调用是一个字符串追加调用,这反过来会产生一些开销:

leaq    16(%rsp), %rdi
movl    $50, %esi
call    std::basic_string<char>::append(char const*, unsigned long)

单独查看代码并不能保证func3比func1快,只是因为它的指令较少。缓存和其他因素也有助于实际表现,只有通过衡量才能正确评估,正如其他人指出的那样。