可能重复:
Is it better to pass by value or by reference for basic datatypes?
Reasons to not pass simple types by reference?
我做了一些测试,其中我有两个场景,每个场景有两个相同的功能 - 一个通过引用传递参数,另一个通过值传递。带有字符串的场景显示了大量的性能提升(因为创建了一个字符串的副本,调用了构造函数),而使用long的测试在通过引用传递值时没有显示任何性能提升。事实上,有时表现更差。
这是原始类型的预期吗?没有必要通过引用传递它们吗?
我原本期望在不使用引用的情况下制作原始类型的副本,因此期望获得较小的性能提升。
答案 0 :(得分:25)
通过按值传递基本类型可以获得最佳性能。这是因为:
double
和long long
大于参考这最后一点经常被忽视,但可以产生相当大的不同。
答案 1 :(得分:8)
是的,这是预期的行为。当您通过引用传递参数时,实际上是在传递变量的地址(就像使用指针一样)。通常地址是一个4或8字节的整数,所以除非你的原始类型大于那个,否则你不会获得任何性能提升(即使它更大,你可能也不会)
答案 2 :(得分:5)
现代编译器非常聪明,所以如果函数不是“隐藏”的(也就是编译器在生成代码时看不到的东西的一部分),它可能完全没有区别。 HOwever,如果编译器遵循您的指示,将简单类型作为参考传递可能会产生很大的不同。特别是如果值在代码中多次更新。
我看到了一些我工作的代码,它做了类似的事情:
void SomeClass::FindLength(int &len)
{
listEntry* list = theList; // theList is a member variable.
len = 0;
while (list)
{
len++;
list = list->next;
}
}
通过替换代码来做:
void SomeClass::FindLength(int &len)
{
listEntry* list = theList; // theList is a member variable.
int tempLen = 0;
while (list)
{
tempLen++;
list = list->next;
}
len = tempLen;
}
整个代码运行速度提高了30%,并且从很多地方调用(我认为中间有一些if条件,所以我们不能只跟踪长度)。由于它是API函数的一部分,因此无法更改函数签名。
使用引用速度较慢的原因是编译器会在每次更新时写入引用值,这是从内存到寄存器,增量寄存器和存储寄存器到内存的加载。使用tempLen
解决方案,编译器可以使用寄存器,这要快得多。
答案 3 :(得分:4)
在c ++中,引用是使用指针的便捷方式。使用指针时,添加其他间接。复制原始类型与复制指针一样便宜。 这就是为什么原始类型通过引用传递得慢一点
答案 4 :(得分:2)
当您通过引用传递值时,该函数必须取消引用它才能获取该值,并且每次修改该值时,由于您将其写入内存位置,因此必须进行取消引用。我猜编译器能够理解何时不会将某些内容存储回其参考位置,以便仅在寄存器上修改该值并在需要时将其存储回来,但我不确定这是多么强大。
因此,有一个间接步骤在按值传递参数时不存在,这会导致性能更差,但由于编译器优化已经到位,因此它确实很模糊。想想你传递一个指针的事实,每次你需要这个值时你必须从堆栈中获取指针然后获取指向的值(所以有两个访问),而使用普通参数你只有一个。< / p>
在任何情况下,引用都用于与性能完全不同的目的。
答案 5 :(得分:1)
因为你使用了c
标签,我想你是在谈论指针(不是来自C ++的显式引用)。
使用指针,您有两个内存访问:指针和指向的值。因此没有特别的表现。此外,编译器可以使用值进行更多优化:例如,没有别名问题。
答案 6 :(得分:1)
这是原始类型的预期吗?
我绝对会说。它们没有构造函数,因此不需要调用。
通过引用传递它们没有意义吗?
当你想要输出参数时,那么,在C ++中,通过引用传递被认为比传递指针更好。
我原本期望在不使用引用的情况下制作原始类型的副本,因此期望获得较小的性能提升。
好吧,因为通过引用传递通常是使用指针实现的,所以编译器必须发出将某些内容推送到堆栈的代码,无论是值还是指向值的指针 - 并且无论哪一个都完成无关紧要