7

假设我们有这种情况

std::string v_1()
{
    return "name";
}
std::string test = v_1();

RVO 在这里应用吗?我认为答案是否定的,因为应用 RVO 的规则之一是:“如果函数按值返回类类型,并且 return 语句的表达式是具有自动存储持续时间的非易失性对象的名称,则t 函数参数,或 catch 子句参数,并且与函数的返回类型具有相同的类型(忽略顶级 cv 限定),则省略复制/移动“并且在这种情况下,返回的对象不具有与函数的返回类型相同的类型,但我不是 100% 不在这里应用 RVO。

非常感谢。

PS。在本次演讲中https://www.youtube.com/watch?v=AKtHxKJRwp4(第 40 分钟,第 18 秒)来自 Microsoft 的 Stephan 谈到了无法应用 RVO 的情况,因为函数的返回类型不同于返回对象的类型(在他的示例中为元组与对)。我认为同样的原则也适用于此。

4

2 回答 2

5

我认为您NRVORVO.

  • NRVO-命名返回值优化
  • RVO-(未命名)返回值优化

NRVO涉及命名变量,而涉及在语句RVO中构造的未命名临时变量。return

视频中的示例是NRVO,当类型不同时,显然无法在调用者堆栈上构造命名对象,因为函数堆栈中必须存在一种类型的对象,而调用者堆栈中必须存在另一种类型的对象.

您的示例是RVO您没有使用预先构造的命名对象的地方。在您的代码中,您正在构建一个临时对象作为返回值。因为它是临时的,所以您引用的规则不适用。

根据C++11标准我看不出为什么RVO不能发生:

12.8复制和移动类对象[ class.copy ] ... 31 ...

-- 当一个没有绑定到引用(12.2)的临时类对象将被复制/移动到具有相同cv-unqualified类型的类对象时,可以通过将临时对象直接构造成来省略复制/移动操作省略复制/移动的目标

通过返回一个char array临时std::string的构造,就是返回给调用者的内容。

于 2016-12-03T19:02:10.497 回答
3

NRVO 和 RVO 是不同的省略情况。

省略是将多个对象的生命周期合并为一个对象。

名称 NRVO 和 RVO 是编译器在标准允许时如何进行省略的名称。

在您的示例中,允许在行中创建的临时return变量、函数的返回值以及存储返回值的命名变量之间进行省略。每个认真的编译器都可以并且将一起省略这些值,除非您明确告诉它不要通过编译器标志。在 C++17 中,这些省略将是强制性的。

于 2016-12-03T20:28:42.720 回答