通过引用存储函数的返回值是否有任何性能提升?我的意思是以下代码是首选,因为它可以防止将函数的返回值复制到变量中?
string Foo()
{
string someString = "some string";
return someString;
}
const string &str = Foo();
编辑:虽然在上面的示例Foo()
中返回一个字符串,但我的问题也涉及返回其他类型的对象。
通过引用存储函数的返回值是否有任何性能提升?我的意思是以下代码是首选,因为它可以防止将函数的返回值复制到变量中?
string Foo()
{
string someString = "some string";
return someString;
}
const string &str = Foo();
编辑:虽然在上面的示例Foo()
中返回一个字符串,但我的问题也涉及返回其他类型的对象。
字符串在 C++ 中实现的方式是一个字符数组。因此,当您使用引用时,主要优点是可以避免按成员进行复制,并且指向的对象是本身已传递的对象。这提高了涉及大字符串或数组的性能。对于您的示例,字符串非常短,并不重要!希望这可以帮助 :)。
不,事实上,性能可能会略有下降(尽管我对此表示怀疑)。在这种情况下,您通过使用引用获得的所有好处都是混淆。
今天的编译器足够聪明,在这种情况下可能会使用 RVO(返回值优化)。所以即使按值返回也不存在复制开销
您应该遵循的主要规则是编写可读性好的代码(因为代码是为人编写的),并且仅在需要时才进行优化,并且仅在发现瓶颈后才进行优化
知道,您不会获得性能提升。在这种情况下,您可以使用 std::move() 来获得提升。
您的代码目前包含两个副本Foo
:
string
(1) 从使用构造函数构造的类型的临时对象const char*
,到someString
.
(2)从变量someString
到临时对象即是返回值Foo
。
您正在编写const string &str = Foo();
而不是const string str = Foo();
为了防止第三次复制:
(3) 从作为 , 的返回值的临时对象Foo
到str
。
标准允许省略所有三个副本,所以问题基本上是您的编译器是否需要 3 的帮助。
根据经验,我会说不——如果你的编译器足够聪明,可以忽略副本 1 和 2,那么它很可能足够聪明,可以忽略 3。如果它不够聪明,不能忽略其中任何一个,这会让你付出代价性能,那么您需要处理函数Foo
以及调用它的代码。但是这种情况不会出现——只要你记得打开优化,任何真正的 C++ 编译器都可以做复制省略。
可以想象,在某些特殊情况下,您需要仔细编写代码以帮助编译器找出无法删除允许删除的副本的地方。您需要在这些情况发生时找到它们,没有一般的编码指南可以(准确地)告诉您您需要担心(3)而不是(1)和(2)。