Joh*_*nes 7 c++ initializer-list return-value-optimization c++11
例:
struct s { int a; };
s func() { return {42}; }
int main() {
s new_obj = func(); // line 6
(void) new_obj;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这有效.现在,如果我们假设我们的编译器没有RVO会发生什么?
func返回一个struct的结构s,因此{42}必须转换为s,然后返回并最终复制到new_obj第6行.func 返回初始化列表,因此无法进行深层复制.语言是什么意思?你能举一个证明吗?
注意:我知道这在这个例子中看起来没用,但是对于返回非常大的常量std::arrays,我不想依赖RVO.
请考虑以下示例:
#include <iostream>
struct foo {
foo(int) {}
foo(const foo&) { std::cout << "copy\n"; }
foo(foo&&) { std::cout << "move\n"; }
};
foo f() {
//return 42;
return { 42 };
}
int main() {
foo obj = f();
(void) obj;
}
Run Code Online (Sandbox Code Playgroud)
当使用gcc 4.8.1编译-fno-elide-constructors以防止RVO输出时
move
Run Code Online (Sandbox Code Playgroud)
如果在f返回语句中没有使用花括号,那么输出就是
move
move
Run Code Online (Sandbox Code Playgroud)
没有RVO,会发生以下情况.f必须创建一个类型的临时对象foo,让我们调用它ret来返回.
如果return { 42 };被使用,则ret是直接从值初始化42.因此到目前为止还没有调用复制/移动构造函数.
如果return 42;使用,那么另一个临时,让我们称之为tmp直接初始化42并tmp移动到创建ret.因此,到目前为止,一个移动构造函数被调用.(注意,这tmp是一个右值并且foo有一个移动构造函数.如果没有移动构造函数,那么将调用复制构造函数.)
现在ret是一个rvalue,用于初始化obj.因此,移动构造器被调用以移动ret到obj.(同样,在某些情况下,可以调用复制构造函数.)因此,一个(for return { 42 };)或两个(for return 42;)移动发生.
正如我在对OP的问题的评论中所说,这篇文章非常相关: 即使XZY具有非复制约束,构造助手make_XYZ也允许RVO和类型推导.尤其是外观极好答案由 R.费尔南德斯Martinho.
| 归档时间: |
|
| 查看次数: |
370 次 |
| 最近记录: |