c++ - 在RVO无法完成的情况下,C++ 应该写 `std::move`?

  显示原文与译文双语对照的内容
130 1

众所周知,std::move 不应应用于函数返回值,因为它可以防止 RVO ( 返回值优化) 。我对这样的问题感兴趣:如果我们知道RVO不会发生,我们应该怎么做。

这就是C++14标准所说的[12.8/32 ]

在符合copy操作或者移动操作elision条件时,当条件声明为指定的对象时,首先执行复制操作。如果对象是指定对象指定的对象,重载解析将首先执行,如果表达式中指定了对象,则重载。如果第一个重载解析失败或者未执行,或者者如果选定构造函数的第一个参数不是对象( 可能是 cv )的右引用。[ 注意:这两个阶段重载解决方案必须执行,无论是否发生复制省略。如果不执行省略,则确定要调用的构造函数,即使调用被忽略,也必须访问选定的构造函数。—结束注释]

这是书 Effective Modern C++的解释

标准欢迎RVO的一部分是,如果满足RVO的条件,但编译器选择不执行复制省略。实际上,标准要求当允许RVO时,复制忽略发生,或者 std::move 隐式地应用到返回的本地对象。

我知道当返回对象不能被省略时,它应该被视为 rvalue在这些示例中,我们可以以看到当传递大于 5 对象的参数时,它被复制。当我们知道RVO不会发生时,是否应该显式写 std::move

#include <iostream>
#include <string>
struct Test
{
 Test() {}
 Test(const Test& other)
 {
 std::cout <<"Test(const Test&)" <<std::endl;
 }
 Test(Test&& other)
 {
 std::cout <<"Test(const Test&&)" <<std::endl;
 }
};
Test foo(int param)
{
 Test test1;
 Test test2;
 return param> 5? std::move(test1) : test2;
}
int main()
{
 Test res = foo(2);
}

这里程序的输出为 Test(const Test&)

时间:原作者:0个回答

96 0

你的例子中发生的不是链接到 RVO,而是与三元 operator?如果使用 if 语句重写示例代码,则程序的行为将是预期的。foo 定义更改为:

Test foo(int param)
 {
 Test test1;
 Test test2;
 if (param> 5)
 return std::move(test2);
 else
 return test1;
 }

将输出 Test(Test&&)

如果你写了(param>5)?std::move(test1):test2是:

因此在示例代码中,移动省略发生,但是在复制初始化需要形成三元运算符的结果之后。

原作者:
...