我想知道引用是如何在内部存储的?我觉得对这个层次有深入的理解,将使我更好地理解指针与引用的概念,并做出正确的决策选择。
我怀疑它的工作原理与指针基本相同,但编译器负责处理指针。请给予建议。
我想知道引用是如何在内部存储的?我觉得对这个层次有深入的理解,将使我更好地理解指针与引用的概念,并做出正确的决策选择。
我怀疑它的工作原理与指针基本相同,但编译器负责处理指针。请给予建议。
引用和指针在编译器内部都是别名,对待方式相同。
但是从用户的角度来看,两者之间存在几个微妙的差异。
其中一些主要的区别包括:
NULL
,而引用不能。不存在所谓的NULL
引用。const
引用可以延长与其绑定的临时对象的生命周期,这在指针中没有类似物。此外,引用与const
指针(而不是指向常量的指针)有一些共同点:
如果你知道你有一个对象需要引用,并且永远不想引用其他任何东西,请使用引用,否则请使用指针。
*((int*)0)
上:你正在解引用一个空指针。你很幸运它没有立即崩溃。如果它没有崩溃,那么是的,你总是可以将其绑定到引用,但这并不能改变一开始解引用指针就是未定义行为这个事实。 - Etienne de Martel很抱歉要用汇编来解释这个问题,但我认为这是理解编译器如何实现引用的最佳方式。
#include <iostream>
using namespace std;
int main()
{
int i = 10;
int *ptrToI = &i;
int &refToI = i;
cout << "i = " << i << "\n";
cout << "&i = " << &i << "\n";
cout << "ptrToI = " << ptrToI << "\n";
cout << "*ptrToI = " << *ptrToI << "\n";
cout << "&ptrToI = " << &ptrToI << "\n";
cout << "refToNum = " << refToI << "\n";
//cout << "*refToNum = " << *refToI << "\n";
cout << "&refToNum = " << &refToI << "\n";
return 0;
}
i = 10
&i = 0xbf9e52f8
ptrToI = 0xbf9e52f8
*ptrToI = 10
&ptrToI = 0xbf9e52f4
refToNum = 10
&refToNum = 0xbf9e52f8
让我们来看一下反汇编(我使用的是GDB。这里的8、9和10是代码的行号)
8 int i = 10;
0x08048698 <main()+18>: movl $0xa,-0x10(%ebp)
这里$0xa
是我们要分配给i
的十进制数10。 -0x10(%ebp)
表示ebp寄存器
的内容减去16(decimal)。 -0x10(%ebp)
指向堆栈上i
的地址。
9 int *ptrToI = &i;
0x0804869f <main()+25>: lea -0x10(%ebp),%eax
0x080486a2 <main()+28>: mov %eax,-0x14(%ebp)
将i
的地址分配给ptrToI
。 ptrToI
再次位于堆栈上,位于地址-0x14(%ebp)
,即ebp
- 20(十进制)。
10 int &refToI = i;
0x080486a5 <main()+31>: lea -0x10(%ebp),%eax
0x080486a8 <main()+34>: mov %eax,-0xc(%ebp)
-0x14(%ebp)
被-0xc(%ebp)
所替换。 -0xc(%ebp)
是refToNum的地址。 它在堆栈上分配。 但您永远无法从您的代码中获取此地址,因为无需知道该地址。16 cout << "*ptrToI = " << *ptrToI << "\n";
0x08048746 <main()+192>: mov -0x14(%ebp),%eax
0x08048749 <main()+195>: mov (%eax),%ebx
19 cout << "refToNum = " << refToI << "\n";
0x080487b0 <main()+298>: mov -0xc(%ebp),%eax
0x080487b3 <main()+301>: mov (%eax),%ebx
-0xc(%ebp)
是 refToI
的实际地址,但你永远无法直接访问它。简单来说,如果你把引用想成一个普通指针,那么访问引用就像获取引用指向的地址中的值。这意味着下面的两行代码将给出相同的结果。cout << "Value if i = " << *ptrToI << "\n";
cout << " Value if i = " << refToI << "\n";
15 cout << "ptrToI = " << ptrToI << "\n";
0x08048713 <main()+141>: mov -0x14(%ebp),%ebx
21 cout << "&refToNum = " << &refToI << "\n";
0x080487fb <main()+373>: mov -0xc(%ebp),%eax
我想你能够看出这里发生了什么。如果你请求&refToI
,那么将返回-0xc(%ebp)
地址位置的内容,-0xc(%ebp)
是refToi
所在的位置,它的内容就是i
的地址。
最后一件事,为什么这行代码被注释掉了?
//cout << "*refToNum = " << *refToI << "\n";
*refToI
是不允许的,这会导致编译时出错。