是否保证在返回时移动对象?

时间:2012-06-18 17:32:33

标签: c++ c++11 return-value move-semantics

我知道当按值将对象传递给函数时,如果有的话,总是调用移动构造函数,假设没有复制省略。如何按值返回对象?

例如,假设我们有一个具有移动构造函数的类Foo,并且我们有一个返回Foo对象的函数。

Foo g() {
    Foo f;

    // do something with f

    return f;
}

如果我们假设没有RVO,那么移动构造函数是否可以保证被调用?

更新:我想我没有明确表达我的意图。我只是想知道我可以在最坏的情况下移动对象而不是复制。无论是RVO还是NRVO,我很高兴。我还应该说移动构造函数和移动赋值不会被删除并且已正确实现。

3 个答案:

答案 0 :(得分:6)

是。见[class.copy] p32

  

当满足或将满足复制操作的省略标准时,除了源对象是函数参数,并且要复制的对象由左值指定,重载决策以选择构造函数首先执行复制,就好像对象是由右值指定的一样。如果重载解析失败,或者所选构造函数的第一个参数的类型不是rvalue引用   对象的类型(可能是cv-qualified),再次执行重载决策,将对象视为左值。 [注意:无论是否发生复制省略,都必须执行此两阶段重载决策。如果未执行elision,它将确定要调用的构造函数,并且即使调用被省略,也必须可以访问所选的构造函数。 - 结束记录]

答案 1 :(得分:2)

在这种情况下,由于返回值具有名称(f),因此它将是适用的NRVO(命名返回值优化)。

因此,仅基于措辞的技术答案是,由于NRVO仍然可以允许,因此RVO的缺失不会阻止复制省略。

过去,我相信返回值的移动/复制之间的选择可以/将取决于Foo的定义 - 肯定会被复制而不是移动,例如,如果你已经明确删除移动构造函数和移动赋值运算符,或者您尚未定义移动构造/赋值,并且它们不能隐式合成它们。

编辑:[回复已编辑的问题]:拥有移动构造函数仍不能保证结果将被移动。一个明显的例子是,如果您删除了移动赋值运算符,并且正在分配结果(而不是使用它来初始化)。在这种情况下,删除的移动赋值运算符将阻止移动返回值。

为了回答你可能已经得到的东西,一般规则是如果可能的话,移动将会完成,当且仅当某些事情阻止了移动结果时,它才会回归复制。

答案 2 :(得分:1)

规则是,只要允许复制省略但未发生复制省略,将使用移动构造函数(如果可用),否则将使用复制构造函数。

确切的行为由[class.copy]/32

定义
  

当满足或将满足复制操作的省略标准时,除了源对象是函数参数,并且要复制的对象由左值指定,重载决策以选择构造函数首先执行复制,就好像对象是由右值指定的一样。如果重载决策失败,或者所选构造函数的第一个参数的类型不是对象类型的rvalue引用(可能是cv-qualified),则再次执行重载决策,将对象视为左值。