【问题标题】:In what cases can't a modern day compiler apply the NRVO optimization for functions?在什么情况下,现代编译器不能对函数应用 NRVO 优化?
【发布时间】:2013-09-07 19:12:19
【问题描述】:

一般来说,我想知道现代编译器(例如使用 c++11 的 gcc 4.7 及更高版本)何时以及为何无法应用 NVRO 优化。

编辑:我错误地过度简化了这段代码,没有返回任何局部变量。 @cooky451 提供了一个更好的例子,见ideone.com/APySue

我看到了一些 sn-ps 代码来回答其他类似的问题

A f(A&& v)
{
  return v;
}

他们被改成了

A f(A&& v)
{
  return std::move(v);
}

因为他们说传递给左值 v 的右值仍然是右值并且可以移动。然而,其他人写道,这将取消 NVRO 的能力。这是吗?如果编译器知道正在返回一个临时对象,它不能直接在原地构造它而不移动任何东西吗?我想我不明白为什么案例一会有 NVRO 而不是案例 2。我可能有错误的事实,因此问题。另外,由于这个原因,我读到案例 2 是一种反模式,您不应该像这样返回 std::move 。任何额外的见解都会有所帮助。有人告诉我,编译器会在幕后创建如下所示的内容:A& __hidden__ 是对函数的赋值,在这种情况下是 myValue。

A myValue = f(A());

// behind the scenes pseudo code for direct in place construction

void f(A&& v,  A& __hidden__ )
{
    __hidden__ = v;
    return;
}

【问题讨论】:

    标签: c++ c++11 move-semantics rvalue-reference copy-elision


    【解决方案1】:

    两者都不会使用 RVO,因为这是不可能的。问题是: && 仍然只是一个参考。您返回的变量不在您的函数局部范围内!所以,没有 std::move,你会复制,然后你会移动。我建议顺便说一句,只要您不编写移动构造函数/赋值运算符或一些完美转发模板代码,就不要期望每个 rvalue-reference 有什么东西。只看价值。在某些情况下,它的开销很小,但实际上并不重要。它使代码更具可读性。而且更简单,因为调用者可以复制或移动参数,并且您不必提供额外的 const& 重载。

    【讨论】:

    • 有道理,我想我过度简化了这个例子。如果返回了本地堆栈变量,那么 NVRO 应该正确发生吗?
    • 仅在第一种情况下,检查ideone.com/APySue 这就是为什么使用 std::move 返回值是一种反模式的原因之一;另一个是如果无法执行 RVO,则自动发生移动以返回 - 试试看。 ;-) 编辑:有时 std::move 返回值是有意义的,但这种情况很少见。不过,您自己找到了一个 - 在使用引用时,尤其是 rvalue-references。
    • 我认为这是我的主要问题,为什么 NVRO 可以应用于第一种情况而不是第二种情况?很好的例子,我会用它来更好地理解这一点。
    • RVO 可能未应用,因为 std::move (en.cppreference.com/w/cpp/utility/move) 实际上返回了一个引用。
    • 因此,如果我只是从 foo() 执行 return A(77),它似乎可以使用 RVO 进行优化。那么是不是因为移动是创建对右值而不是右值本身的引用,所以它无法执行此操作?我相信这就是你所说的。
    猜你喜欢
    • 2012-05-18
    • 1970-01-01
    • 2013-06-28
    • 2015-09-15
    • 1970-01-01
    • 2017-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多