如何在不妨碍RVO的情况下确保移动?
How to ensure moving without impeding RVO?
从函数返回对象时,假设定义了移动和复制构造函数,则自C++11以来可能会发生以下情况之一(另请参阅本文末尾的示例):
- 它符合复制消除条件,编译器执行 RVO。
- 它符合复制省略的条件,编译器不执行 RVO,但随后......
- 它符合移动构造函数的使用条件并被移动。
- 以上都不是,并且使用复制构造函数。
前 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.案例,执行 RVO,现场演示,生成的汇编器:
A callee1(){
A a(0);
return a;
}
2. 示例: 1.案例,RVO执行,现场演示,结果汇编器:
A callee2(bool which){
return which? A(0) : A(1);
}
3. 示例: 2.案例,符合复制要求,RVO未执行,现场演示,结果汇编:
A callee3(bool which){
A a(0);
A b(1);
if(which)
return a;
else
return b;
}
4. 示例: 3.case,不符合复制省略条件(x
是一个函数参数),但用于移动,现场演示,生成的汇编程序:
A callee4(A x){
return x;
}
5. 示例: 4.案例,没有复制或隐式移动(见此SO-post),现场演示,结果汇编程序:
A callee5(bool which){
A a(0);
A b(1);
return which ? a : b;
}
6. 示例: 4.案例,没有复制或隐式移动,现场演示,结果汇编:
A callee6(){
std::pair<A,int> x{0,1};
return x.first;
}
什么时候不能执行 RVO?
如果以下任何情况适用,编译器(通常)无法执行 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
怎么办?我们可以通过在条件中显式构造它来处理这种情况。在这种情况下,构造的值保证经历RVO,因为三元的两侧都产生一个prvalue。
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
。
- 在没有太多条件句的情况下,我如何避免被零除
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 在未初始化映射的情况下,将值插入到映射的映射中
- 是默认情况下分配给char数组常量的值
- 为什么我不能在不创建字符串变量的情况下使用函数的字符串输出
- 如何在不产生任何垃圾的情况下获得C中的像素
- 在已经使用Git的情况下减少编译时间
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- 如何在没有信号的情况下从C++执行QML插槽
- 如何在不知道向量大小的情况下输入向量内部的向量?
- 为什么在某些情况下不写入此文件?
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 在没有Xcode的情况下在Mac捆绑包中嵌入框架
- UE4-如何在给定4个屏幕坐标的情况下缩放纹理或材质
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 在C++中如何在没有pow的情况下进行基础计算
- 如何在不妨碍RVO的情况下确保移动?
- 如何确保在MULTIMAP的情况下分配的内存被释放
- 我如何确保在有多个候选函数的情况下调用正确的函数
- 如何在禁用C++异常的情况下确保内存不足的稳健性(VS2010)