从C ++ 11开始,从函数返回对象时,假设定义了移动构造函数和复制构造函数,则可能发生以下情况之一(另请参见本文结尾处的示例):
对于前3种情况,建议不要使用显式的std::move
,因为无论如何都会执行移动,并且可能会阻止可能的RVO,请参见此SO-post。
但是,在4.情况下,显式std::move
将提高性能。但是,由于有些人既不懂标准又不懂汇编程序,所以需要花很多时间来区分情况1-3和4。
我的问题:有没有一种方法可以以统一的方式处理上述所有情况,例如:
以下是一些示例,也可以用作测试用例。
所有示例均使用以下helper-class-definition:
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.大小写不符合复制删除条件(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;
}
答案 0 :(得分:3)
如果满足以下任一条件,则编译器通常无法执行RVO:
在情况1中,您应该使用std::move
或使用if
语句而不是三元运算符来编写代码。在情况2中,您必须使用std::move
。在情况3中,您还应该显式使用std::move
。
处理情况1。我们可以依靠if
语句(而不是三元运算符)返回局部变量来确保值被移动:
A whichOne(bool which) {
A a(0);
A b(1);
if(which) {
return a;
} else {
return b;
}
}
如果您真的更喜欢使用三元运算符,请在两个条件上明确使用std::move
:
A whichOne(bool which) {
A a(0);
A b(1);
return which ? std::move(a) : std::move(b);
}
如果我只想移动a
而不是b
会怎样?我们可以通过在条件条件中显式构造它来处理这种情况。在这种情况下,由于三元数的两边都会产生 prvalue ,因此可以保证构造值接受RVO。
A whichOne(bool which) {
A a(0);
A b(1);
return which
? A(std::move(a)) // prvalue move-constructed from a
: A(b); // prvalue copy-constructed from b
}
处理情况2和3。很简单:返回对象的成员,或者返回来自数组或指针的引用时,请使用std::move
。