请考虑三个功能。
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;
}
有什么想法吗?
答案 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)
这取决于你的编译器 - 你指的是什么平台?最好的方法是编译一个 very 小测试应用程序并检查编译器生成的ASM。
是的,没关系,但你从不提及你所关心的事情;速度?样式?你可以将一个本地临时的const引用 - 临时的生命周期将延长到引用的生命周期 - 试试看看吧! (Herb Sutter对此here进行了解释。)例如,见帖子末尾。
IMO你几乎总是更好地相信你的编译器为你优化你的代码。在极少数情况下你需要关心这类事情(非常低级别的代码是一个这样的区域,你可以与硬件寄存器交互)。
int foo() { return 42; }
int main(int, char**)
{
const int &iRef = foo();
// iRef is valid at this point too!
}