【问题标题】:When is RVO garanteed to apply / does apply with C++20 compilersRVO 何时保证适用/确实适用于 C++20 编译器
【发布时间】:2019-10-06 22:49:18
【问题描述】:

C++ 核心指南指出

F.20:对于“输出”输出值,首选返回值而不是输出 参数

但随后给出以下异常:

struct Package {      // exceptional case: expensive-to-move object
    char header[16];
    char load[2024 - 16];
};

Package fill();       // Bad: large return value
void fill(Package&);  // OK

不应该是返回值优化的情况吗?在这种情况下是否可以防止 RVO?或者仍然不如通过引用有效?还是有些编译器做不到?

更一般地说,我什么时候应该依赖像传递引用技术一样高效地优化返回值的编译器?

【问题讨论】:

    标签: c++ compiler-optimization c++20 rvo


    【解决方案1】:

    在 C++17 中保证“普通”RVO(即返回纯右值或常用术语中的“临时”)并在此之前得到很好的支持。

    NRVO(即,返回一个局部变量)可能很挑剔并且无法保证,如果没有执行,那么你会得到一个移动。如果您的搬家成本很高,您可能希望避免这种情况。

    在示例中,fill 很有可能需要使用后者。

    【讨论】:

    • 好的,我现在明白了。 Fill 大概会构造一个默认对象(因此是一个命名对象)然后初始化它(例如std::fill),这意味着我们处于 NRVO 的情况下,这不会被优化
    【解决方案2】:

    还是没有引用传递那么高效?

    如果 RVO 适用,则返回值与使用输出引用一样有效。

    在这种情况下是否可以防止 RVO?

    没有。 “大”并不妨碍对象被 RVO。

    RVO 何时保证适用/确实适用于 C++20 编译器

    不适用的情况:

    ...如果操作数不是纯右值或其类型与函数的返回类型不同,则返回语句可能涉及调用构造函数以执行操作数的复制或移动。

    所以,是否保证复制省略取决于函数的实现。

    指南确实未能解释为什么应该遵循该建议。

    请注意,异常表示:

    例外

    如果一个类型的移动成本很高(例如,array<BigPOD>),请考虑将其分配到免费存储并返回一个句柄(例如,unique_ptr),或者将其传递给 non -const 要填充的目标对象(用作输出参数)。

    异常中突出显示的建议对我来说更有意义。它清楚地表明对象太大而无法堆栈,从而减少堆栈溢出的机会。

    【讨论】:

      猜你喜欢
      • 2014-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-26
      • 1970-01-01
      • 2019-07-30
      • 2014-11-26
      • 2012-02-28
      相关资源
      最近更新 更多