有一天我意外地注意到了这一点,现在决定对它进行广泛的测试。
所以,当我调用一个函数时:
#define Type int
#define Prm const Type &
Type testfunc1(Prm v1, Prm v2, Prm v3, Prm v4, Prm v5, Prm v6, Prm v7, Prm v8, Prm v9, Prm v10){
return (v1|v2|v3|v4|v5|v6|v7|v8|v9|v10);
}
1亿次:
for(Type y = 0; y < 10000; y++){
for(Type x = 0; x < 10000; x++){
out |= testfunc1(x,y,x,x,y,y,x,y,x,y);
}
}
对于int
,const int
和const int &
类型,我注意到const int
比const int &
快。 (注意:我使用返回值来确保函数不会被优化掉)。
为什么会这样?我一直认为添加&
实际上会让它更快,但测试却反过来说。我知道对于更大的数据类型,它可能会有不同的结果,但我没有测试过,因为我对结果非常肯定。
我的测试:
const int: 7.95s
const int &: 10.2s
编辑:我认为这确实是因为我的架构;我使用Sint64
类型进行了测试,结果是:
const Sint64: 17.5s
const Sint64 &: 16.2s
编辑2:或者是吗?用double
类型(64位?)进行测试,结果让我感到困惑:
const double: 11.28s
const double &: 12.34s
Edit3:更新了循环代码,使我的最新测试与64位类型匹配。
答案 0 :(得分:9)
通过在参数中加入&
,您将向程序添加更多代码。如果没有&
,则序列为:
push values
call Function
pop values <- usually an update to stack pointer
和功能:
return sp[arg1] | sp[arg2] | etc <- value read direct from stack.
添加'&amp;'这样做:
push address of value1
push address of value2
etc
call Function
pop values <- usually an update to stack pointer
和功能:
return_value = 0;
address = sp[arg1]
or return_value, [address]
address = sp[arg2]
or return_value, [address]
etc
return return_value
因此,正如您所看到的,&
增加了很多。那么为什么要用呢?如果你有一个非常大的对象,传递指针比将对象复制到堆栈更合理。
答案 1 :(得分:7)
此结果严重依赖于系统。它表明在您的特定系统上复制引用的值(最有可能实现为指针)比复制整数值的成本更高。这种差异的最可能原因是您的整数需要32位来表示,而您的指针/引用表示需要64位。 编辑这就是访问整数的成本:获取它们的值需要额外的间接。由于您只传递了两个项目,因此使用缓存会在很大程度上隐藏额外的成本,但成本就在那里。
你对大型类型绝对正确:将引用传递给大型struct
或vector<...>
仍然只需要64位(或者系统中的大小),无论您的结构有多少项目,或vector<...>
拥有多少项目。结构越大,通过价值传递的成本就越高,因此通过将其作为参考来实现节省。
答案 2 :(得分:1)
传递地址而不是值会导致地址转义(在您喜欢的编译器教科书中查找转义分析或指向分析),使得优化更加困难。
是的,内联和链接时优化等内容可以缓解这些问题。