【发布时间】:2019-04-29 08:52:19
【问题描述】:
当从函数返回对象时,自 C++11 以来可能会发生以下情况之一,假设定义了移动和复制构造函数(另请参见本文末尾的示例):
- qualifies for copy-elision 和编译器执行 RVO。
- 它符合复制省略的条件,编译器不执行 RVO,但是...
- 它qualifies for the usage of move constructor 被移动了。
- 以上都没有,并且使用了复制构造函数。
前 3 种情况的建议是不要使用显式 std::move,因为无论如何都会执行移动并且可能会阻止可能的 RVO,例如,请参见 SO-post。
但是,在第 4 种情况下,显式 std::move 会提高性能。但作为一个既不熟悉标准也不流利阅读汇编程序的人,区分情况 1-3 和 4 需要花费大量时间。
因此我的问题是:有没有办法以统一的方式处理所有上述情况,例如:
- RVO 不受阻碍(案例 1)
- 如果不执行 RVO,则使用移动构造函数(案例 2,3 和 4)
- 如果没有移动构造函数,则应使用复制构造函数作为后备。
这里有一些例子,也可以作为测试用例。
所有示例都使用以下帮助程序类定义:
struct A{
int x;
A(int x_);
A(const A& a);
A(A&& a);
~A();
};
1.示例: 1.case,RVO 执行,live-demonstration,resulting assembler:
A callee1(){
A a(0);
return a;
}
2。示例: 1.case,RVO 执行,live-demonstration,resulting assembler:
A callee2(bool which){
return which? A(0) : A(1);
}
3.示例: 2.case,符合复制省略,RVO 未执行,live-demonstration,resulting assembler:
A callee3(bool which){
A a(0);
A b(1);
if(which)
return a;
else
return b;
}
4.示例: 3.case,不符合复制省略(x 是函数参数),但对于移动,live-demonstration,resulting assembler:
A callee4(A x){
return x;
}
5.示例: 4.case,没有复制省略或隐式移动(见SO-post),live-demonstration,resulting assembler:
A callee5(bool which){
A a(0);
A b(1);
return which ? a : b;
}
6.示例: 4.case,没有复制省略或隐式移动,live-demonstration,resulting assembler:
A callee6(){
std::pair<A,int> x{0,1};
return x.first;
}
【问题讨论】:
-
不是一个真正的答案,但 gcc 和 clang 已经开始警告悲观的举动:godbolt.org/z/ZkpDgB
标签: c++ c++11 language-lawyer rvo