【发布时间】:2017-06-10 23:23:25
【问题描述】:
看这样一段代码(添加了cmets):
std::string some_var;
std::string some_func(); // both are defined, but definition is irrelevant
...
return "some text " + some_var + "c" + some_func(); // intentionally "c" not 'c'
我想知道,在哪些情况下 operator + 或 std::string 必须进行复制(在使用复制构造/分配的意义上,而不是复制的内部缓冲区,例如,如果 SSO 应用),以及实际复制的内容。快速查看cppreference 只是部分有用,因为它列出了 12(!)个不同的案例。在某种程度上,我要求确认我对页面的理解:
- 案例 1) 制作 lhs 的副本,然后将 rhs 复制到此副本的末尾
- 在 C++98 案例 2) - 5) 中,从
char/const char*参数构造一个临时字符串,然后导致案例 1) - 在 C++11 案例 2) - 5) 中,临时字符串由
char/const char*参数,然后导致情况 6) 或 7) - 在 C++11 案例 6) - 12) 中,r-value 参数将被
insert/append改变,如果提供了char/const char*参数,则由于insert/append上的重载,不需要临时参数。在所有情况下,都会返回一个 r 值以促进进一步的链接。不制作副本(除了要在插入位置附加/插入的参数的副本)。可能需要移动字符串的内容。
因此,像上面示例这样的链应该导致:2) -> 6) -> 11) -> 8),不会复制任何 lhs,而只是修改 r-value 的缓冲区导致从第一个操作(创建临时字符串)开始。
因此,这似乎与operator += 一样有效,一旦operator + 至少使用 r-value 参数。这是正确的吗,在 C++11 及之后的版本中使用 operator += 而不是 operator + 有什么意义,除非这两个参数都是左值字符串?
编译器还可以进行哪些优化?
编辑:澄清问题的意图。最初的部分仅是关于语言的细节(实现非承受);最后一个问题是关于额外的优化。
【问题讨论】:
-
修正了我认为的错字。如果您的意思是
some_fun(),请回滚。 -
并不是真正的错字,但我想你的版本在 c++ 上下文中更清晰。
-
使用
g++ -save-temps编译并查看不同优化级别的汇编程序输出是很有启发性的。使用-O3,它会为您的代码调用一次string::reserve()和四次string::append()。 -
@G.Sliepen:更简单:使用compiler explorer
-
老实说,我更关心在增长字符串时重新分配复制的性能,而不是按已建立的值返回,因为它很可能得到了相当好的优化。
标签: c++ c++11 stl language-lawyer stdstring