鉴于以下内容:
Foo getFoo()
{
Foo result = doSomeWork();
return result;
}
C ++是否保证移动result
而不是复制?换句话说,写return std::move(result)
是多余的?
是否有任何(其他)情况,标准指定在没有明确的std::move
演员表的情况下静默移动左值而不是复制左眼?
备注:
假设Foo
是可移动构造的。
无视复制/移动省略,可另外申请。
答案 0 :(得分:4)
尽管可能会忽略此举,但是。如果移动构造函数可用,则永远不会发生副本。为清楚起见,我会再次引用该段落。 [class.copy] / 32:
满足复制/移动操作的省略标准时,但是 不是异常声明,和要复制的对象 由左值指定,或在
return
中表达时 statement是一个(可能带有括号的) id-expression ,用于命名 具有在体内声明的自动存储持续时间的对象 首先执行最内层封闭函数的 parameter-declaration-clause 或 lambda-expression , 重载决策以选择复制的构造函数,就好像该对象由一个 右值即可。如果第一个重载决议失败或没有 执行,或者如果所选的第一个参数的类型 构造函数不是对象类型的右值引用(可能 cv-qualified),重新执行重载决策,考虑到 对象作为左值。 [注意:这个两阶段的重载决议必须 无论是否会发生复制,都会执行。它 如果没有执行elision,则确定要调用的构造函数, 并且即使呼叫是必须的,也必须可以访问所选的构造函数 省略。 - 结束记录]
应用std::move
并不是多余的,但实际上会阻止复制省略,[class.copy] / 31:
- 在具有类返回类型的函数的
return
语句中,何时 表达式是非易失性自动对象的名称 [..]
是的,有一种情况 - 我再次假设您的意思是如果没有执行复制省略,则移动完成(如果移动左值,则必须适用复制省略,s.a。) 考虑一下:
A a;
throw a;
符合标准:
- 在 throw-expression 中,当操作数是a的名称时 非易失性自动对象(函数或catch子句除外) 参数)其范围不超出最内层的末端 封闭try-block(如果有的话),复制/移动操作 异常对象(15.1)的操作数可以省略 将自动对象直接构造到异常对象
Demo。
这是移动左值而不是复制左手的唯一其他情况;复制省略的另外两种情况仅包括未绑定到引用的临时(因此必须由prvalues指定)和异常声明的东西,这在这里是无趣的,因为它涵盖了我们看不到的异常对象。
答案 1 :(得分:0)
我认为这是一个返回值优化的案例。
http://en.wikipedia.org/wiki/Return_value_optimization
编译器根本不会复制或移动对象,而是识别它。
所以,不,我不会写return std::move(result)
它甚至可能使编译器无法优化。