我正在从函数返回非命名对象。为什么 RVO 仍然在发挥作用?

I'm returning non-named object from a function. Why RVO still kicks in?

本文关键字:RVO 为什么 作用 对象 函数 返回      更新时间:2023-10-16

关于这个:为什么std::move阻止RVO? 有人写道:"因此,在返回语句中,只有在表达式是局部变量的名称时,才会发生复制省略"

但是,我用GCC做了一些测试:

class X
{
public:
    X()
    {
        cout << "def" << endl;
    }
    X(const X& x)
    {
        cout << "copy" << endl;
    }
    X(X&& x)
    {
        cout << "move" << endl;
    }
};
X produceX()
{
    return X();
}
int main()
{
    X x{produceX()};
    return 0;
}

produceX 函数不返回命名值。它返回一个未命名的临时对象。然而,RVO仍然踢,没有复制或移动结构。来自 main 的 x 对象是就地构造的。如果我这样写 produceX:

X produceX()
{
    X localNamedObject;
    return localNamedObject;
}

它的行为方式相同(这是预期的)。但是为什么在前一种情况下允许RVO?

这种说法过于简单化,尽管你从中得到的答案实际上回答了这个问题,并提供了标准中的相关文本。

在返回临时变量

(作为使用临时初始化相同类型的对象的一般情况)以及返回局部变量时,允许复制省略。

在按值抛出和捕获异常时也允许这样做,但这超出了本问题的范围。

RVO 代表"返回值优化",是指直接在返回值空间内构造返回表达式结果的技术。当返回表达式为右值时,将应用它。

NRVO 代表"命名返回值优化",指的是构造最终将直接在返回值空间内返回的命名对象的技术。当返回表达式为左值时,将应用它。