了解返回值优化和返回临时值 - C ++

时间:2009-09-08 14:05:35

标签: c++ compiler-construction return-value-optimization

请考虑三个功能。

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. 可以在上面的代码中返回临时内容吗?我相信它没关系,因为我按值返回它而不是返回任何引用它。
  3. 有什么想法吗?

4 个答案:

答案 0 :(得分:16)

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

您可以在Scott Meyers书籍More Effective C++. 35 New Ways to Improve Your Programs and Designs的第20项中阅读有关RVO的更多信息。

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

答案 1 :(得分:7)

首先,完全可以返回临时值,这就是你所做的。它被复制,虽然原件将超出范围,但副本不会这样做,并且可以被调用者安全地使用。

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

答案 2 :(得分:2)

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

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
}

工作得很好。在这种情况下,没有涉及建筑或复制结构。只需该函数返回对其参数的引用。

答案 3 :(得分:1)

  1. 这取决于你的编译器 - 你指的是什么平台?最好的方法是编译一个 very 小测试应用程序并检查编译器生成的ASM。

  2. 是的,没关系,但你从不提及你所关心的事情;速度?样式?你可以将一个本地临时的const引用 - 临时的生命周期将延长到引用的生命周期 - 试试看看吧! (Herb Sutter对此here进行了解释。)例如,见帖子末尾。

  3. IMO你几乎总是更好地相信你的编译器为你优化你的代码。在极少数情况下你需要关心这类事情(非常低级别的代码是一个这样的区域,你可以与硬件寄存器交互)。

    int foo() { return 42; }
    
    int main(int, char**)
    {
        const int &iRef = foo();
        // iRef is valid at this point too!
    }