在 C++ 中,通过引用传递原始类型而不是按值返回是否有效率优势?
3 回答
[...] 通过引用传递原始类型而不是按值返回是否有效率优势?
不太可能。首先,除非您从探查器获得的数据为您提供了这样做的理由,否则您在设计程序时不应该担心性能问题。选择最简单的设计,以及最能传达您的意图的设计。
此外,原始类型通常复制起来很便宜,因此这不太可能成为您的应用程序的瓶颈。而且由于它是最简单的选项,也是使函数界面最清晰的选项,因此您应该按值传递。
只看签名,很明显有这样一个函数:
void foo(int);
不会存储对参数的引用(因此,不会遇到悬空引用或指针等问题),不会以调用者可见的方式更改参数,等等。
以上都不能从函数签名中推断出来,例如:
void f(int&); // May modify the argument! Will it? Who knows...
甚至:
void f(int const&); // May store a reference! Will it? Who knows...
此外,通过值传递甚至可以通过允许编译器执行潜在别名会阻止的优化来提高性能。
当然,所有这一切都是假设您实际上不需要修改函数内部的参数,即在函数返回后调用者可以看到该参数的副作用 - 或存储对该参数的引用争论。
如果是这种情况,那么您当然应该通过引用传递并使用适当的const
资格。
如需更广泛的讨论,另请参阅StackOverflow 上的问答。
一般来说,不会有任何性能优势,而且很可能会有性能成本。考虑这段代码:
void foo(const int& a, const int& b, int& res) {
res = a + b;
res *= a;
}
int a = 1, b = 2;
foo(a, b, a);
当编译器遇到像 add() 这样的函数时,它必须假设 a 和 res 可能像示例调用中那样具有别名,因此如果没有全局优化,它将不得不生成加载 a、加载 b、然后将 a + b 的结果存储到的代码res,然后再次加载 a 并执行乘法运算,然后将结果存储回 res。
相反,如果您这样编写函数:
int foo(int a, int b) {
int res = a + b;
res *= a;
return res;
}
int a = 1, b = 2;
int c = foo(a, b);
然后编译器可以将 a 和 b 加载到寄存器中(甚至直接在寄存器中传递它们),在寄存器中进行加法和乘法然后返回结果(在许多调用约定中可以直接在生成它的寄存器中返回) .
在大多数情况下,您实际上希望 foo 的按值传递/返回版本中的语义和按引用传递/返回版本中可能的别名语义实际上并不需要得到支持。通过使用通过/返回参考版本,您最终可能会付出真正的性能损失。
Chandler Carruth在 C++ Now 上做了一个很好的演讲。
在这种情况下可能存在一些晦涩的架构,但我不知道返回内置类型的性能低于通过引用传递 out 参数的任何地方。如果需要,您可以随时检查相关的程序集进行比较。