请考虑这三个功能。

std::string get_a_string()
{
    return "hello";
}

std::string get_a_string1()
{
    return std::string("hello");
}

std::string get_a_string2()
{
    std::string str("hello");
    return str;
}
  1. RVO 是否适用于这三种情况?
  2. 像上面的代码一样返回一个临时值可以吗?我相信这是可以的,因为我是按值返回它而不是返回对它的任何引用。

有什么想法吗?

有帮助吗?

解决方案

在前两种情况下,将进行 RVO 优化。RVO 是旧功能,大多数编译器都支持它。最后一种情况称为 NRVO(命名为 RVO)。这是 C++ 相对较新的功能。标准允许但不要求实现 NRVO(以及 RVO),但某些编译器支持它。

您可以在 Scott Meyers 的书第 20 条中阅读有关 RVO 的更多信息 更有效的 C++。改进程序和设计的 35 种新方法.

这里 是一篇关于 Visual C++ 2005 中的 NRVO 的好文章。

其他提示

首先,按值返回临时值是完全可以的,这就是您所做的。它被复制,尽管原始文件会超出范围,但副本不会这样做,并且可以由调用者安全地使用。

其次,所有三种情况实际上都是相同的(因为无论如何在第三种情况下您都不会访问临时数据),编译器甚至可能为所有情况发出相同的代码。因此它可以在所有三种情况下使用 RVO。这完全取决于编译器。

所有情况都是正确的。它们都会构造一个临时对象并应用返回类型的复制构造函数。如果没有复制构造函数,代码必然会失败。

在大多数编译器下,这三种情况都会发生 RVO。唯一的区别是最后一项,标准没有强制要求它。这是因为你有一个命名变量。但大多数编译器足够聪明,仍然可以将 RVO 应用于它......命名变量声明得越晚,应用的转换越少,RVO 应用于命名变量的可能性就越大。

顺便说一句,返回引用当然是可能的,正如您在其他代码中看到的那样。您不能做的是返回本地对象的引用。

std::string& get_a_string2()
{
    std::string str("hello");
    return str; //error!
}

如您所知,会产生编译时错误。然而,

std::string& get_a_string2(std::string& str)
{
    // do something to str
    return str; //OK
}

会工作得很好。在这种情况下,不涉及任何构造或复制构造。简单来说,函数返回对其参数的引用。

  1. 这取决于您的编译器 - 您指的是哪个平台?找出答案的最佳方法是编译一个 非常 小测试应用程序并检查编译器生成的 ASM。

  2. 是的,没关系,尽管你从未提及你所关心的事情;速度?风格?您可以将本地临时变量转换为 const 引用 - 临时变量的生命周期将延长到引用的生命周期 - 亲自尝试一下!(赫伯·萨特解释了这一点 这里)例如,请参阅帖子末尾。

在我看来,你最好相信你的编译器会为你优化你的代码。在极少数情况下,您需要关心这类事情(非常低级的代码就是这样的区域,您在其中与硬件寄存器交互)。

int foo() { return 42; }

int main(int, char**)
{
    const int &iRef = foo();
    // iRef is valid at this point too!
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top