通过 const reference 或 by value 传递 int,有什么区别吗?
Pass int by const reference or by value , any difference?
当我将 int
和 double
之类的原语传递给函数时,是通过 const 引用传递它们更好,还是通过值传递它们更好(假设我不更改变量的值)?
int getValueFromArray(int index)
{
// return the value from the array
}
int getValueFromArray(const int& index)
{
// return the value from the array
}
谢谢
很大程度上取决于编译器的优化级别。编译器优化可能会使整点变得毫无意义。实施架构也在某种程度上发挥了作用。但是,一般来说,按值传递应该会稍微好一点。
它有助于理解引用实际上只是一个指针,上面加了一些糖。因此,检索参数的值涉及将此指针参数从堆栈中取出,然后进行另一个解引用以获取该值,而不是直接从堆栈中读取参数的值。
但本质上的差异主要是学术上的。当参数不仅仅是一个 int 值时,这个问题就变得更加重要。然后,选择归结为传递引用,而不需要进一步的工作,而不是制作参数 class 的实例的副本。这可能很贵。
如果你通过 const 引用传递 int,你最终将付出一层(不必要的)间接层的代价来访问它的值,除非一个非常聪明的优化器检测到它可以只通过值传递 int在任何情况下。
有时通过 (const) 引用传递和 int 是有意义的,但只有在您编写模板代码并且不想为 int
这样的原始数据类型创建额外的特化时才有意义。在正常情况下,你最好通过值而不是 const 引用传递 int
,特别是在很多硬件上,当你处理带有签名的函数时,可以将 int 传递到寄存器中的函数你上面的那些。即使不是,它就在堆栈中,具有良好的参考位置。
使用 double
情况会有所不同,因为在某些体系结构上,将引用或指向双精度值的指针传递给函数比传递值本身更有效。但是,在最近的硬件上,与仅传递值相比,由于间接层,您很可能会失去性能。
在这两种情况下,compiler/linker 具有相当积极的内联,尤其是 link 时间代码生成将能够优化代码以避免在处理堆栈时传递任何参数代码生成器将内联的更小的实用函数。
如果数据类型适合处理器的寄存器,则通过副本(值)传递。较大的项目应通过引用传递。
您应该打印出两个示例的汇编语言列表,没有优化和高度优化。使用更好的编译器,编译器将识别模式并执行最佳选择,通常是按值传递。
在汇编语言列表中,您可以看到编译器如何执行任何优化。
没有优化的最坏情况,常量引用通常是通过指针传递来实现的。因此,指针将位于寄存器中,而不是将值放在寄存器中。这意味着无论何时您访问该变量,您都会首先解除对指针的引用。这可能是一些额外的指令或处理器周期,但在执行和程序方面可能并不重要 space。
对于原始类型,按值传递比按引用传递要好得多。不仅没有间接寻址,而且有了引用,编译器不得不担心潜在的别名,这会破坏优化机会。
最后,按引用传递导致左值变为 odr-used,这实际上会导致链接器错误。如果内联调用,最后一个问题不会消失。
当我将 int
和 double
之类的原语传递给函数时,是通过 const 引用传递它们更好,还是通过值传递它们更好(假设我不更改变量的值)?
int getValueFromArray(int index)
{
// return the value from the array
}
int getValueFromArray(const int& index)
{
// return the value from the array
}
谢谢
很大程度上取决于编译器的优化级别。编译器优化可能会使整点变得毫无意义。实施架构也在某种程度上发挥了作用。但是,一般来说,按值传递应该会稍微好一点。
它有助于理解引用实际上只是一个指针,上面加了一些糖。因此,检索参数的值涉及将此指针参数从堆栈中取出,然后进行另一个解引用以获取该值,而不是直接从堆栈中读取参数的值。
但本质上的差异主要是学术上的。当参数不仅仅是一个 int 值时,这个问题就变得更加重要。然后,选择归结为传递引用,而不需要进一步的工作,而不是制作参数 class 的实例的副本。这可能很贵。
如果你通过 const 引用传递 int,你最终将付出一层(不必要的)间接层的代价来访问它的值,除非一个非常聪明的优化器检测到它可以只通过值传递 int在任何情况下。
有时通过 (const) 引用传递和 int 是有意义的,但只有在您编写模板代码并且不想为 int
这样的原始数据类型创建额外的特化时才有意义。在正常情况下,你最好通过值而不是 const 引用传递 int
,特别是在很多硬件上,当你处理带有签名的函数时,可以将 int 传递到寄存器中的函数你上面的那些。即使不是,它就在堆栈中,具有良好的参考位置。
使用 double
情况会有所不同,因为在某些体系结构上,将引用或指向双精度值的指针传递给函数比传递值本身更有效。但是,在最近的硬件上,与仅传递值相比,由于间接层,您很可能会失去性能。
在这两种情况下,compiler/linker 具有相当积极的内联,尤其是 link 时间代码生成将能够优化代码以避免在处理堆栈时传递任何参数代码生成器将内联的更小的实用函数。
如果数据类型适合处理器的寄存器,则通过副本(值)传递。较大的项目应通过引用传递。
您应该打印出两个示例的汇编语言列表,没有优化和高度优化。使用更好的编译器,编译器将识别模式并执行最佳选择,通常是按值传递。
在汇编语言列表中,您可以看到编译器如何执行任何优化。
没有优化的最坏情况,常量引用通常是通过指针传递来实现的。因此,指针将位于寄存器中,而不是将值放在寄存器中。这意味着无论何时您访问该变量,您都会首先解除对指针的引用。这可能是一些额外的指令或处理器周期,但在执行和程序方面可能并不重要 space。
对于原始类型,按值传递比按引用传递要好得多。不仅没有间接寻址,而且有了引用,编译器不得不担心潜在的别名,这会破坏优化机会。
最后,按引用传递导致左值变为 odr-used,这实际上会导致链接器错误。如果内联调用,最后一个问题不会消失。