【问题标题】:Returning an empty string : efficient way in c++返回一个空字符串:C++ 中的有效方式
【发布时间】:2014-12-22 14:31:09
【问题描述】:

我有两种从函数返回空字符串的方法。

1)

std::string get_string()
{
   return "";
}

2)

std::string get_string()
{
   return std::string();
}

哪一个更有效,为什么?

【问题讨论】:

  • 两者都不是。使用return {};
  • 这与 C 有什么关系?
  • 这属于无用的微优化领域,您的编译器将使用 RVO 和复制省略进行优化。
  • @KerrekSB 你能详细说明原因吗?
  • 因为它是使用默认构造函数的直接初始化,而不是复制初始化(来自可能动态评估的构造函数)。如果您的实现如此倾向于,默认构造函数可以实现为无分配 constexpr。

标签: c++ string performance


【解决方案1】:

Gcc 7.1 -O3 这些都是相同的,godbolt.org/z/a-hc1d – jterm 4 月 25 日 3:27

原答案:

做了一些挖掘。下面是一个示例程序和相关程序集:

代码:

#include <string>

std::string get_string1(){ return ""; }

std::string get_string2(){ return std::string(); }

std::string get_string3(){ return {}; }           //thanks  Kerrek SB

int main()
{
    get_string1();
    get_string2();
    get_string3();
}

组装:

__Z11get_string1v:
LFB737:
    .cfi_startproc
    pushl   %ebx
    .cfi_def_cfa_offset 8
    .cfi_offset 3, -8
    subl    $40, %esp
    .cfi_def_cfa_offset 48
    movl    48(%esp), %ebx
    leal    31(%esp), %eax
    movl    %eax, 8(%esp)
    movl    $LC0, 4(%esp)
    movl    %ebx, (%esp)
    call    __ZNSsC1EPKcRKSaIcE
    addl    $40, %esp
    .cfi_def_cfa_offset 8
    movl    %ebx, %eax
    popl    %ebx
    .cfi_restore 3
    .cfi_def_cfa_offset 4
    ret $4
    .cfi_endproc

__Z11get_string2v:
LFB738:
    .cfi_startproc
    movl    4(%esp), %eax
    movl    $__ZNSs4_Rep20_S_empty_rep_storageE+12, (%eax)
    ret $4
    .cfi_endproc

__Z11get_string3v:
LFB739:
    .cfi_startproc
    movl    4(%esp), %eax
    movl    $__ZNSs4_Rep20_S_empty_rep_storageE+12, (%eax)
    ret $4
    .cfi_endproc

这是用-std=c++11 -O2编译的。

您可以看到 return ""; 语句的工作量要多得多,而 return std::stringreturn {}; 的工作量则相对较少(这两个是相同的)。

正如 Frerich Raabe 所说,当传递一个空的C_string 时,它仍然需要对其进行处理,而不仅仅是分配内存。看来这不能被优化掉(至少不是通过 GCC)

所以答案肯定是使用:

return std::string();

return {};   //(c++11)

尽管除非您在性能关键代码中返回 很多 空字符串(我猜是日志记录?),但差异仍然是微不足道的。

【讨论】:

  • 也许这需要从 2017 年起进行更新,所有三种可能性返回都会产生相同的 asm 结果,因此返回 "" 或 std::string{} 或 {} 没有问题。在编译器资源管理器上测试了 clang & gcc
  • @TomazCanabrava 我当时应该注意到 gcc 版本...如果您想提供您测试过的 clang 和 gcc 版本,我会在答案中注明。
  • @TomazCanabrava 实际上,当我尝试使用上述 gcc 和 clang 时,我得到了类似的结果(gcc 7.1/clang4.0.0)。有趣的是,Visual Studio (2015) 提供的结果在每个版本之间都是一致的,但在所有情况下都做得更多。
  • 另外值得注意的是return {};是C++扩展,所以return std::string();应该是首选。
【解决方案2】:

后一个版本永远不会比第一个慢。第一个版本使用 C 字符串调用 std::string 构造函数,然后必须首先计算字符串的长度。尽管这对于空字符串来说很快,但肯定不会比不做更快。

【讨论】:

  • 因为它是一个被返回的常数,长度计算是否没有被编译器优化掉?如果没有,可能吗?
  • @Baldrickk 他正在调用std::string 的单参数构造函数。我不认为有很多(如果有的话)编译器足够聪明地推断出一个参数构造函数相当于构造函数同时接受一个指针和一个大小,只要它传递的小于字符串的大小文字(有一个尾随 '\0')。
  • @JamesKanze:一些编译器在字符串文字上优化strlen() - 十多年前我要求将该功能添加到 SparcWorks C++ - 不知道他们是否做过 - GCC 已经做过那时候。仍然 - 我不一定期望 C++ 实现使用 strlen... 永远不知道。
  • @JamesKanze 确认了你所说的。看我的回答。
猜你喜欢
  • 2012-07-04
  • 1970-01-01
  • 2019-10-29
  • 2011-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多