c++ - 为什么 RVO 要求如此严格?

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

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

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

为什么RVO的规则对于函数返回类型为Treturn表达式类型为T&&<的情况不做异常(exception)处理

我也知道在编译器中实现这些东西并不是免费的。我只是建议允许但不是必需的这种异常(exception)。

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


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

最佳答案

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&& return),您不知道它是否确实绑定(bind)到临时值,您不知道该值何时创建以及何时超出范围,或者即使您知道你不能像上面的例子那样改变它的构造和销毁点。

I'm not sure that I fully understand. If RVO were allowed to be applied to test(), why would that be worse than if test did: T temp = foo(); return temp; which would allow NRVO?

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

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

    return temp; // NRVO allowed
}

但是使用 return foo() 你不能仅仅因为你不知道返回引用绑定(bind)到哪个对象而忽略了拷贝。它可以是对任何对象的引用。

关于c++ - 为什么 RVO 要求如此严格?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49380956/

相关文章:

c++ - C++负数中对1位的计数

c++ - 输出中意外的换行

c++ - 在 CreateProcess 之后调用 GetModuleFileNameEx 时出现 ERROR_INVALID_HANDLE

c# - 如何将对象列表从 C++ 传递到 C#?

c++ - 连接元组作为类型

c++ - 模板代码中的类型不完整

php - 定义目录时末尾有/没有 '/' 有什么区别?

c - 有微 Controller 的 C 标准吗?

C++ 和网络套接字

c++ - 进入函数,但不进入 VS2017 的参数评估