【问题标题】:Forcing RVO / move construction when returning by value按值返回时强制 RVO/移动构造
【发布时间】:2012-11-13 11:46:39
【问题描述】:

假设我有一个带有复制构造函数和移动构造函数的对象 'foo',以及一个函数

foo f() {
    foo bar;
    /* do some work */
    return bar;
}

标准似乎声明编译器将尝试执行以下操作:NRVO,按右值返回 ref,按值返回,失败;按这个顺序。

有什么方法可以强制编译器永远不按值返回,因为我的复制构造函数非常昂贵?

【问题讨论】:

  • 您是否分析并确定存在实际瓶颈?
  • 标准定义了NRVO?给我的消息...
  • (我承认它允许 NRVO)
  • 它“允许”NRVO,并“允许”通过右值引用返回,但似乎也不需要,除非它们确实发生了优先级。本质上,我想要求其中任何一种发生,但绝不是某些任意函数 foo f(); 中的复制构造函数;
  • f() 总是按值返回,从不返回右值引用。 NRVO 表示bar 构造在适当的位置以获取返回值。如果 bar 是可移动的,那么如果 NRVO 不能完成,则返回值是从 bar 构造的移动。这似乎是您所说的“按 r 值 ref 返回”的意思,但这不是一个准确的描述。如果它不能移动,那么它是复制构造的。这似乎就是您所说的“按价值回报”的意思,但这也不准确。同样f() 总是按值返回,返回值如何构造的内部细节不会改变这一点。

标签: c++ c++11 rvalue-reference move-constructor return-value-optimization


【解决方案1】:

编译器会尝试做:NRVO,return by r-value ref,return by value,失败;按这个顺序。

上述措辞不准确,可能表明您存在误解。编译器可以使用 NRVO(大多数情况下),如果不可用,它将总是按值返回,区别在于返回值的构造方式。如果您的类型具有移动构造函数,编译器必须使用该构造函数,并且只有在您的类型没有移动构造函数时才会使用复制构造函数。

也就是说,如果您的类型具有移动构造函数,则使用复制构造函数的编译器将不符合 C++11。

【讨论】:

  • 从我对 g++ 和 clang 的测试来看,当 NRVO 不起作用时,它看起来像是使用了复制构造函数。见ideone.com/zoeixm。仅当您执行 return std::move(...) 时,它才会使用移动构造函数。不过,我不确定这是否是标准规定的,或者编译器是否不够聪明,无法处理这种情况。
  • 好的,看起来三元是导致问题的原因。将return flag ? t : f; 扩展为if (flag) return t; else return f; 使其使用移动构造函数。原因是三元表达式的结果是B&
  • @hyperair:原因并非如此(return t; 中的t 也是B&),但如果对您有帮助,您可以将其用作提醒。真正的原因是编译器通常不能移出 lvalue,标准中有一组固定的异常,特别是在返回语句when表达式是非易失性自动对象的名称 (12.8/31)。大胆的脸是我的。在return t; 中,表达式是名称,可以省略副本,如果不是,则必须移动对象。 return cond ? t : r;不是这样的
【解决方案2】:

如果foo 有一个有效的移动构造函数,您的代码将永远不会通过副本返回。

【讨论】:

    【解决方案3】:

    您也可以使用输出参数而不是返回:

    void f(foo& bar) { ... }
    

    但实际上所有编译器都会执行NVRO

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-14
      • 2020-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多