还有一个“为什么std::move必须阻止(未命名的)返回值优化?”问题:
为什么性病::移动防止RVO?解释说,标准明确要求函数的声明返回类型必须与return语句中表达式的类型匹配。这解释了符合编译器的行为;但是,它并没有解释限制的理由。
为什么对于函数的返回类型为T而return表达式的类型为T&&的情况,RVO的规则不例外
我还意识到,在编译器中实现这些东西并不是免费的。我只是建议允许但不需要这样的例外。
我也知道return std::move(...)是不必要的,因为C++11 已经要求在无法应用RVO时使用移动语义。然而,为什么不容忍一个明确的优化要求,而不是把它变成悲观呢?
(旁白:为什么return-value-optimization和rvo标签不是同义词?)
发布于 2018-03-20 10:12:44
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
}寓意:只有你知道的真值,你才能确定你有一个暂时的,最重要的,你知道它的确切寿命,这样你才能避免它的构造和破坏。但是对于xvalue(例如T&&返回),您不知道它是否确实绑定到临时值,您不知道该值是何时创建的,何时超出范围,或者即使您知道不能更改它的构造和破坏点,如上面的示例所示。
我不确定我是否完全理解。如果RVO被允许应用于
test(),为什么会比测试更糟糕:允许NRVO的T temp = foo(); return temp;?
并不是说情况更糟。这是不可能的。在您的示例中,temp是要应用NRVO (即test )的函数中的一个局部变量。因此,它是一个在上下文中完全“已知”的对象,它的生存期是已知的,ctor和dtor的正常点是已知的。因此,它不是在调用方的堆栈帧中创建temp变量,而是在调用方的堆栈帧中创建。这意味着从test的堆栈帧到调用方的堆栈帧没有对象的副本。还请注意,在本例中,foo()完全不相关。它可能是temp初始化过程中的任何东西。
auto test() -> T
{
T temp = /*whatever*/;
return temp; // NRVO allowed
}但是,使用return foo(),您不能仅仅因为无法知道返回引用绑定到哪个对象而删除副本。它可以是对任何对象的引用。
https://stackoverflow.com/questions/49380956
复制相似问题