Use of & operator in C++ function parameters: pass-by-rvalue-reference
我对这个代码片段有点惊讶!调用方正在传递值,但函数如何处理其地址?
1 2 3 4 5 6 7 8
| void increase1(int &value) {
value++;
}
int main() {
int number = 5;
increase1(number);
} |
如果有人详细解释的话会很有帮助。谢谢您。
- 查找"参考"
- 当&出现在这样的函数参数(或任何类型名称)中时,它是一个修饰符,而不是一个运算符。
- @因此,如果我们将变量声明为int &i。这到底是什么意思?
- 只能将未初始化的引用声明作为结构或类内的成员变量进行。作为引用的局部或全局变量必须立即绑定。例如,您可以有一个循环for( int i = 0; i < v.size(); ++i ) { int &r = v[i]; /* read and write using r */ }。
- 有很多重复:在C++函数签名中使用ANP和运算符,C++函数参数列表中的什么?,函数原型中的和号是什么意思?
'increase1(int&value)'采用'l-value引用'。在C++ 11之前,我们只学习了"引用"。所有参考均为L值。
L值是什么?L值的简化定义是编译器可以提供地址的东西。因此,变量(如value)具有物理存储位置(假设其内存位置没有优化)。
一个标量,如5,甚至是两个变量的和,如x + y都没有内存位置。编译器不在内存中存储5。相反,它将一个5移动到number的存储位置。编译器不将x + y存储为内存位置。同样,在简化的基础上,5是一个概念,(x+y)是一个概念——这些是r值。对r值的引用是第二种引用类型[此处不讨论]。
回到您的好例子,int &value描述了一个l值引用,因为value表示内存中的一个位置。
main()函数(假设没有优化)
声明number为int,并为number分配、存储。在大多数32位和64位系统上,为数字分配了4个字节的内存。
5是R值。编译器创建一条移动指令,将5移动到内存中的数字位置。
main()现在通过传递数字的存储位置来调用increase1()。变量是通过引用传递的,这意味着地址被传递给increase1。main()知道传递地址,因为'increase1()接受L值引用。
increase1()接收到数字的地址,将其解引用得到5个值,在解引用的指针上加一个,然后将结果存储回地址为number的位置。
L值引用允许被调用函数直接修改调用方拥有的存储。
请注意,存储地址是传递的。地址可以来自main()的堆栈,也可以来自堆(由new分配)。在本例中,main()从堆栈中分配number,但不必从堆栈中分配。
一种非常冗长的说法,即L值引用将使用地址传递,除非编译器认识到它可以通过优化更快地传递。如果编译器优化了引用的实际通道,那么逻辑理解仍然有效。
- 感谢您提供详细的答案。它清楚地解释了背景中发生的事情。所以,简单地说,我们将地址传递给函数(这是自动完成的)。
- 对。我发现在谈论int& variable时总是使用"L值引用"这个术语很有帮助,因为还有两种类型的引用需要学习。
这是一个参考。
1 2 3
| `int a; //variable
int @a; //reference
int *a; //pointer` |
引用就像一个指针,您必须先初始化,不能更改。但您可以更改该地址的值。在申报之后,你不需要在它之前加*号。
右声明示例:int &a=b;现在要使用它,只需写A,当你改变A时,同样的改变也会发生在B上。
由于increase1引用int,调用者自动通过引用发送值。
通过引用发送值的功能与发送指针的功能相同,但
- 你不必记地址,它会自动记下来的
- 可以像使用正则变量一样使用引用
- 假定引用不为空。这很有用,因为这意味着您不必在接受引用的函数内执行空检查。
如果引用来自指针,请在将指针转换为引用之前检查以确保指针不为空。如果您已经知道指针不是空的,那么您就不必检查(当然)。
- 所以引用是自动处理的,我们可以像变量一样使用引用。明白了,谢谢。@ Jorge Perez
- 是啊!这就是证明人很好的原因。)而且,没有办法重新分配证明人,所以你不能意外地更改它所证明的内容。