【问题标题】:When are lvalues moved instead of copied in C++?什么时候左值被移动而不是在 C++ 中复制?
【发布时间】:2015-02-26 00:46:41
【问题描述】:

鉴于以下情况:

Foo getFoo()
{
    Foo result = doSomeWork();
    return result;
}
  • C++ 是否保证result 将被移动,而不是被复制?或者换一种说法,写return std::move(result)是多余的吗?

  • 在没有明确的 std::move 强制转换的情况下,是否存在标准指定左值将被静默移动而不是复制的任何(其他)情况?

注意事项:

  • 假设 Foo 是可移动构造的。

  • 忽略复制/移动省略,这可能会另外应用。

【问题讨论】:

  • 1) 是的。 2) No. 1) 也被歪曲了,因为标准没有“保证result被移动”;实际上,可以省略整个构造函数。正确的是关于构造函数重载决议的一组更窄的规则。
  • @KerrekSB 2) 也可以,例如抛出异常可能会通过 move-ctor IIRC 复制初始化异常
  • std::move() 实际上会抑制 NRVO。
  • 你没有要求这个,但原因是因为很明显resultreturn声明之后没有进一步的用途。大多数其他情况并不那么明显,因此标准更难以对其进行推理。
  • @DanNestor:当然,这一切都在本节末尾的 [class.copy] 中,目前是 12.8。

标签: c++ move move-semantics


【解决方案1】:
  1. 尽管移动可能会被忽略,是的。如果移动构造函数可用,则永远不会发生副本。为了清楚起见,我将再次引用该段落。 [class.copy]/32:

    当满足删除复制/移动操作的条件时,但 不适用于异常声明要复制的对象是 由左值指定,或者当 return 中的表达式 语句是一个(可能用括号括起来的)id-expression,它命名一个 具有在正文中声明的自动存储持续时间的对象或 parameter-declaration-clause 最内层的封闭函数或 lambda-expression 重载分辨率以选择复制的构造函数首先执行好像该对象由一个指定 右值。如果第一个重载决议失败或没有 执行,或者如果选择的第一个参数的类型 构造函数不是对对象类型的右值引用(可能 cv 限定),再次执行重载决议,考虑到 对象作为左值。 [注意: 这个两阶段的重载决议必须 无论是否会发生复制省略,都将执行。它 如果不执行省略,则确定要调用的构造函数, 并且选择的构造函数必须是可访问的,即使调用是 省略。 ——结束注释 ]

    应用std::move 不是多余的,但实际上防止复制省略被执行,[class.copy]/31:

    — 在具有类返回类型的函数中的 return 语句中,当 表达式是非易失性自动对象的名称 [..]

  2. 是的,一种情况 - 我再次假设您的意思是,如果不执行复制省略,则完成移动(如果移动左值,复制省略必须适用,s.a.)。
    考虑一下:

    A a;
    throw a;
    

    满足条件:

    ——在 throw-expression 中,当操作数是一个名称时 非易失性自动对象(函数或 catch 子句除外 参数),其范围不超出最内层的末尾 封闭的try-block(如果有的话),复制/移动操作 异常对象(15.1)的操作数可以省略 将自动对象直接构造到异常对象中

    Demo.
    这是移动左值而不是复制左值的唯一其他情况。复制省略的其他两种情况仅包括未绑定到引用的临时对象(因此必须由 prvalues 指定)和异常声明 thingy,这在这里很无趣,因为它涵盖了我们看不到的异常对象。

【讨论】:

  • 请注意,当类型不同时需要std::move,例如,函数返回std::unique_ptr<Base>,但您返回的变量类型为std::unique_ptr<Derived>
【解决方案2】:

我认为这是一个返回值优化的案例。 http://en.wikipedia.org/wiki/Return_value_optimization 编译器根本不会复制或移动对象,而是识别它。 所以,不,我不会写 return std::move(result) 它甚至可能阻止编译器优化。

【讨论】:

    猜你喜欢
    • 2011-10-26
    • 1970-01-01
    • 1970-01-01
    • 2020-06-04
    • 2011-09-17
    • 2010-09-18
    • 2010-09-25
    • 2020-07-11
    • 2013-05-15
    相关资源
    最近更新 更多