【问题标题】:I'm returning non-named object from a function. Why RVO still kicks in?我正在从函数返回未命名的对象。为什么 RVO 仍然起作用?
【发布时间】:2015-02-10 00:28:28
【问题描述】:

对此:Why does std::move prevent 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 呢?

【问题讨论】:

  • 它是允许的,因为 C++ 标准说它是。变量没有必须被命名。引用要么不正确,要么断章取义。
  • 因为“因此,如果表达式是局部变量的名称,则只有在返回语句中才会出现复制省略”不正确。

标签: c++ c++11 rvo


【解决方案1】:

该声明过于简化,尽管您从中得出的答案确实回答了这个问题,并提供了标准中的相关文本。

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

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

【讨论】:

  • 有人能指出标准中的一个特定句子,即在返回临时文件时可以应用 RVO 吗?另外,这是否意味着 std::move 不会阻止 RVO 并且他们错了?
  • @rubix_addict:就在你引用那句话的答案中。 C++11 [class.copy] 12.8/31,第三个项目符号。
  • “另外,这是否意味着 std::move 不会阻止 RVO” - 不,条件是“临时类对象......将被复制/移动”。 std::move 的结果是引用,而不是临时对象,所以省略不适用。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-19
    • 1970-01-01
    • 2017-09-23
    • 2018-07-24
    • 2020-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多