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

发布于 2024-08-03 17:57:42 字数 353 浏览 2 评论 0原文

请考虑这三个功能。

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. 像上面的代码一样返回一个临时值可以吗?我相信这是可以的,因为我是按值返回它,而不是返回对它的任何引用。

有什么想法吗?

Please consider the three functions.

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. Will RVO be applied in all the three cases?
  2. Is it OK to return a temporary like in the above code? I believe it is OK since I am returning it by value rather than returning any reference to it.

Any thoughts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

¢好甜 2024-08-10 17:57:42

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

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

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

In two first cases RVO optimization will take place. RVO is old feature and most compilers supports it. The last case is so called NRVO (Named RVO). That's relatively new feature of C++. Standard allows, but doesn't require implementation of NRVO (as well as RVO), but some compilers supports it.

You could read more about RVO in Item 20 of Scott Meyers book More Effective C++. 35 New Ways to Improve Your Programs and Designs.

Here is a good article about NRVO in Visual C++ 2005.

一世旳自豪 2024-08-10 17:57:42

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

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

First, it's completely okay to return a temporary by value which is what you do. It is copied and though the original will go out of scope the copy will not do so and can be safely used by the caller.

Second, all three cases are in fact identical (since you don't access the temporary in the third case anyway) and a compiler might even emit the same code for all of them. Hence it can use RVO in all three cases. This is entirely compiler-dependent.

迟到的我 2024-08-10 17:57:42

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

在大多数编译器下,这三种情况都会发生 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
}

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

All cases are correct. They all will construct a temporary and apply the copy constructor of the return type. Necessarily, if there is no copy constructor, the code will fail.

RVO will happen on all three cases under most compilers. Only difference is the last one where the standard does not force it. This because you have a named variable. But most compilers are smart enough to apply RVO to it still... the later the named variable is declared and the less transformations it is applied to, the better odds for RVO to be applied to a named variable.

Incidentally, returning a reference is of course possible as you might have seen in other code. What you must not do is return a reference t a local object.

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

Will produce a compile time error, as you know. However,

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

Will work just fine. On this case, there's no construction or copy construction involved. Simply the function returns a reference to its argument.

小鸟爱天空丶 2024-08-10 17:57:42
  1. 这取决于您的编译器 - 您指的是哪个平台?找出答案的最佳方法是编译一个非常小的测试应用程序并检查编译器生成的 ASM。

  2. 是的,没关系,虽然你从来没有提到你关心的事情;速度?风格?您可以将本地临时变量转换为 const 引用 - 临时变量的生命周期将延长到引用的生命周期 - 亲自尝试一下! (赫伯·萨特对此进行了解释 此处)例如,请参阅帖子结尾。

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

int foo() { return 42; }

int main(int, char**)
{
    const int &iRef = foo();
    // iRef is valid at this point too!
}
  1. It depends on your compiler - what platform are you referring to? Best way to find out is to compile a very small test app and check the ASM your compiler produces.

  2. Yes, it is OK, although you never mention what you're concerned about; speed? style? you can a local temporary to a const reference - the lifetime of the temporary will be extended to the lifetime of the reference - try it and see for yourself! (Herb Sutter exaplins this here) See end of post for example.

IMO you're almost always better off trusting your compiler to optimise your code for you. There are very few cases where you should need to care about this sort of thing (very low level code is one such area, where you're interactive with hardware registers).

int foo() { return 42; }

int main(int, char**)
{
    const int &iRef = foo();
    // iRef is valid at this point too!
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文