C++ 返回空字符串:c+中的有效方法+;
我有两种从函数返回空字符串的方法 (一) (二)C++ 返回空字符串:c+中的有效方法+;,c++,string,performance,C++,String,Performance,我有两种从函数返回空字符串的方法 (一) (二) 哪一个更有效?为什么 后一个版本永远不会比前一个版本慢。第一个版本调用采用C字符串的std::string构造函数,然后必须首先计算字符串的长度。即使对空字符串这样做很快,但肯定不会比根本不这样做快 Gcc 7.1-O3这些都是相同的,godbolt.org/z/a-hc1d–jterm 4月25日3:27 原始答复: 做了一些挖掘。下面是一个示例程序和相关组件: 代码: 这是用-std=c++11-O2编译的 您可以看到,return''还有很
哪一个更有效?为什么 后一个版本永远不会比前一个版本慢。第一个版本调用采用C字符串的
std::string
构造函数,然后必须首先计算字符串的长度。即使对空字符串这样做很快,但肯定不会比根本不这样做快
Gcc 7.1-O3这些都是相同的,godbolt.org/z/a-hc1d–jterm 4月25日3:27
原始答复:
做了一些挖掘。下面是一个示例程序和相关组件:
代码:
这是用-std=c++11-O2
编译的
您可以看到,return''还有很多工作要做代码>语句,对于returnstd::string
和return{}来说相对较少代码>(这两个是相同的)
正如Frerich Raabe所说,当传递一个空的C_字符串时,它仍然需要对其进行处理,而不仅仅是分配内存。这似乎无法优化(至少GCC无法优化)
因此,答案是明确使用:
return std::string();
或
尽管除非在性能关键型代码(我想是日志记录?)中返回大量空字符串,否则差异仍然很小。两者都不是。使用返回{}代码>。这与C有什么关系?这属于无用的微优化领域,编译器将使用RVO和复制省略进行优化。@KerrekSB您能详细说明原因吗?因为它是使用默认构造函数直接初始化,而不是复制初始化(从可能动态计算的构造函数)。如果您的实现非常倾向于将默认构造函数实现为无分配constexpr。由于它是一个返回的常量,编译器是否没有优化长度计算?如果不是,可能是吗?@Baldrickk他正在调用std::string
的单参数构造函数。我不认为有多少(如果有的话)编译器足够聪明,可以推断单参数构造函数等同于同时使用指针和大小的构造函数,只要它传递的值小于字符串文本的大小(后面有一个'\0'
)。@JamesKanze:一些编译器优化strlen()在字符串文字上,我要求这个特性在十多年前被添加到SpCcWorksC++中,不知道他们是否曾经这么做过——GCC已经做过了。不过,我并不一定期望C++实现使用<代码>斯特伦< /代码>…“我也不知道。”詹姆斯坎茨证实了你的话。请看我的答案。可能这需要从2017年起进行更新。所有三种可能的返回都会产生相同的asm结果,因此返回“”或std::string{}或{}不会有任何问题。在编译器资源管理器上测试clang&gcc@TomazCanabrava我当时应该注意到gcc版本。。。如果你想提供你测试过的clang和gcc版本,我会在回答中注意到这一点。@TomazCanabrava实际上,当我尝试使用上面的gcc和clang时,我得到了类似的结果(gcc 7.1/clang4.0.0)。有趣的是,Visual studio(2015)提供的结果在每个版本之间都是一致的,但在所有情况下都做了更多的工作代码>是C++扩展,所以<代码>返回STD::StReg();<代码>应该是首选。
std::string get_string()
{
return std::string();
}
#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
return std::string();
return {}; //(c++11)