为什么RVO要求如此限制?

时间:2018-03-20 09:50:10

标签: c++ c++11 standards rvo return-value-optimization

又一个"为什么std::move必须阻止(未命名)返回值优化?"问题:

Why does std::move prevent RVO?解释说,该标准特别要求函数的声明返回类型必须与return语句中表达式的类型匹配。这解释了符合编译器的行为;但是,它没有解释限制的理由。

为什么RVO的规则在函数的返回类型为Treturn表达式的类型为T&&的情况下不会例外?< / p>

我也知道在编译器中实现这些东西并不是免费的。我建议只允许这样的例外但不是必需的。

我也知道自C ++ 11 already requires that move semantics be used when the RVO can't be applied以来return std::move(...)是不必要的。然而,为什么不容忍明确的优化请求而不是将其变成悲观化?

(旁白:为什么return-value-optimizationrvo标签不是同义词?)

1 个答案:

答案 0 :(得分:19)

auto foo() -> T&&;

auto test() -> T
{
    return foo();
}

你说在这种情况下应该允许应用RVO。但请考虑foo的合法实施:

T val;

auto foo() -> T&&
{
   return static_cast<T&&>(val); // because yes, it's legal
}

道德:只有prvalues你肯定知道你有一个临时的,最重要的,你知道临时的确切寿命,所以你可以忽视它的建设和破坏。但是使用xvalues(例如T&&返回),您不知道这是否确实与临时绑定,您不知道该值何时创建以及何时超出范围,或者即使你知道你不能像上面的例子那样改变它的构造和破坏点。

  

我不确定我完全理解。如果允许RVO   应用于test(),为什么会比测试更糟糕:T temp = foo(); return temp;哪个会允许NRVO?

并不是说情况更糟。这是不可能的。您的示例temp是您要应用NRVO的函数中的局部变量,即test。因此,在test的上下文中,它是完全&#34;已知&#34; 的对象,其生命周期已知,ctor和dtor的正常点已知。因此,不是在temp的堆栈帧中创建test变量,而是在调用者的堆栈帧中创建它。这意味着从test的堆栈帧到调用者的堆栈帧没有对象的副本。另请注意,在此示例中foo()完全无关紧要。它可能是temp的初始化中的任何内容:

auto test() -> T
{
    T temp = /*whatever*/;

    return temp; // NRVO allowed
}

但是使用return foo(),您不能仅仅因为您无法知道返回引用所绑定的对象而忽略该副本。它可以是任何对象的引用。