C++ 为什么常量int比常量int&;快;?

C++ 为什么常量int比常量int&;快;?,c++,visual-c++,C++,Visual C++,有一天我无意中注意到了这一点,现在我决定对它进行广泛的测试 因此,当我调用函数时: #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); } 一亿次: for(

有一天我无意中注意到了这一点,现在我决定对它进行广泛的测试

因此,当我调用函数时:

#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);
}
一亿次:

        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);
            }
        }
编辑:我认为这确实是因为我的架构;我使用
Sint64
类型进行测试,结果如下:

const Sint64: 17.5s
const Sint64 &: 16.2s
Edit2:还是这样?使用
double
类型(64位?)进行测试,结果让我感到困惑:

const double: 11.28s
const double &: 12.34s

Edit3:更新循环代码,使其与我的最新测试与64位类型相匹配。

此结果严重依赖于系统。它表明在您的特定系统上,复制引用的值(很可能实现为指针)比复制整数的值成本更高。造成这种差异的最可能原因是整数需要32位来表示,而指针/引用表示需要64位编辑更不用说访问整数的成本:获取它们的值需要额外的间接操作。因为您只传递两个项目,所以使用缓存在很大程度上隐藏了额外的成本,但成本是存在的


不过,对于较大的类型,您是绝对正确的:传递对大型
struct
vector
的引用仍然只需要64位(或系统上的大小),而不管您的结构有多少项,或者
vector
包含多少项。结构越大,按值传递的成本就越高,因此通过将其作为参考实现的节约也就越高。

在参数中加入
&
,就是在程序中添加更多的代码。如果没有
,则顺序为:

 push values
 call Function
 pop values <- usually an update to stack pointer

因此,正如您所看到的,
&
增加了很多。那为什么要用它呢?如果您有一个非常大的对象,传递指针比将对象复制到堆栈中更为理想。

传递地址而不是值会导致地址转义(在您最喜欢的编译器教科书中查找转义分析或指向分析),使优化更加困难


是的,像内联和链接时间优化这样的事情可以缓解这些问题。

使用返回值并不能确保它不会得到优化。这样,整个计算可以在编译时完成,因此编译器可以优化所有内容,用简单的
0x3FFF
替换循环。我对这个问题的答案很感兴趣。可能是函数prolog代码(由编译器输入)对const int的处理方式不同于const int&。我在做一个有根据的猜测。@R.MartinhoFernandes,好吧,如果它确实优化了它,它在7.95秒内不会执行它;)更不用说我的编译器肯定没有那么聪明(只有在我给参数提供常量值的情况下,它才能对其进行优化)。选择内联函数的一个原因是编译器通常可以将这两种情况优化为相同的情况。您是否真的使用-O2或-O3(或windows上的发布模式)进行编译?即使指针只需要32位,访问实际的int值需要一个间接寻址,这可能是造成差异的原因。即使复制
int
比复制地址更昂贵,参考版本还涉及间接内存获取操作,其成本可能与复制
int
@R.martinhofernands的成本相等。如果您是正确的,则存在间接寻址的成本。OP中的测试在某种程度上隐藏了成本,因为他将只传递两个变量的地址,而不是十个,所以缓存将提供八个间接访问服务,但你是对的,成本仍然存在。@BenVoigt你是对的,我编辑了答案来提到这个区别。@Rookie:计算机是复杂的野兽。虽然你可以做出有根据的猜测,但你通常无法用纯粹的理由得到这样的问题的答案——你实际上必须测试它。(有时,周围的代码甚至会产生更快的影响!)我还应该补充一点,上面是一个一般性的描述。优化人员可以将值放入寄存器而不是堆栈中。IA64编译器还可以将参数放入寄存器中。加1表示寄存器。
 push values
 call Function
 pop values <- usually an update to stack pointer
 return sp[arg1] | sp[arg2] | etc <- value read direct from stack.
 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