引用的本质

转载 2016年08月31日 14:26:59

转载至:点击打开链接


一、引用的本质是什么

说到引用,一般C++的教材中都是这么定义的:

1,引用就是一个对象的别名。

2,引用不是值不占内存空间。

3,引用必须在定义时赋值,将变量与引用绑定。

那你有没有想过,上面的定义正确吗?编译器是如何解释引用的?

这里先给出引用的本质定义,后面我们再进一步论证。

1,引用实际是通过指针实现的。

2,引用是一个常量指针。

3,引用在内存中占4个字节。

4,在对引用定义时,需要对这个常量指针初始化。

二、探究本质

我们从最简单的变量的定义开始,看编译器会做哪些事情。

int var = 42;
mov         dword ptr [var],2Ah  // 对应汇编代码

上面语句申请了一块内存空间,占4个字节,存放了一个int型的变量。内存里放的是42的二进制码。

汇编代码向我们表达的意思就是把42写入以var为地址的内容区域。var有点像我们理解上的指针,只是编译器并没有把它抽象出来,而是让我们更表象的理解:申请一个变量,它的值为42。

那么var这个变量名放在哪呢

我们知道程序如果访问内存里的数据,需要通过地址来进行访问,所以上面的代码在经过编译器生成目标代码时,用存放42的地址了所有的var,所以结论时,目标文件中不存在var,所以变量名本身是不占内存的

而我们知道,引用是变量的一个别名。那么,从这很多人会联想到,引用会不会也只是一个名字而已,编译器在生成目标代码的时候,会用实际地址替换引用呢?

答案并非这样!

那我们接下来看看,当我们定义一个引用时,发生了什么:

1     int var = 42; 
2 01303AC8  mov         dword ptr [var],2Ah  
3     int&  refVar = var; 
4 01303ACF  lea         eax,[var]  
5 01303AD2  mov         dword ptr [refVar],eax 

上面的代码显示,当定义一个引用时,编译器将var的地址赋给了以refVar为地址的一块内存区域。也就是说refVar其实存放的是var的地址。

这让我们联想到了指针,那么我们看看定义一个指针是发生了什么:

1     int var = 42; 
2 01213AC8  mov         dword ptr [var],2Ah  
3     int* ptrVar = &var; 
4 01213ACF  lea         eax,[var]  
5 01213AD2  mov         dword ptr [ptrVar],eax 

没错,没有任何差别,定义一个引用和一个指针的汇编代码完全一致!

三、const哪里去了

相信从上面的分析时,你可能已经相信了,引用实际上就是一个指针。那么为什么说引用是一个常量指针呢,在目标代码里有什么体现呢?

这个问题其实要从C++底层机制谈起,C++为我们提供的各种存取控制仅仅是在编译阶段给我们的限制,也就是说编译器确保了你在完成任务之前的正确行为,如果你的行为不正确,那么编译器就是给你在编译时提示错误。所谓的const和private等在实际的目标代码里根本不存在,所以在程序运行期间只要你愿意,你可以通过内存工具修改它的任何一个变量的值。

这也就解释了为什么上面的两段代码中引用和指针的汇编代码完全一致。

C++设计引用,并用常量指针来从编译器的角度实现它,目标是为了提供比指针更高的安全性,因为常量指针一旦与变量地址绑定将不能更改,这样降低了指针的危险系数,它提供了一种一对一的指针。

但是你觉得使用引用就安全了吗?它同样会有与使用指针一样的问题

1 int *var = new int(42); 
2 int &ref = *var; 
3 delete var; 
4 ref = 42; 
5 return 0;

上面这段代码就很不安全,因为ref引用的内存区域不合法。

为了进一步验证引用与指针在本质上的相同,我们看当引用作为函数参数传递时,编译器的行为:

 1 void Swap(int& v1, int& v2); 
 2 void Swap(int* v1, int* v2);
 3 
 4     int var1 = 1; 
 5 00A64AF8  mov         dword ptr [var1],1  
 6     int var2 = 2; 
 7 00A64AFF  mov         dword ptr [var2],2  
 8     Swap(var1,var2); 
 9 00A64B06  lea         eax,[var2]  
10 00A64B09  push        eax  
11 00A64B0A  lea         ecx,[var1]  
12 00A64B0D  push        ecx  
13 00A64B0E  call        Swap (0A6141Fh)  
14 00A64B13  add         esp,8  
15     Swap(&var1, &var2); 
16 00A64B16  lea         eax,[var2]  
17 00A64B19  push        eax  
18 00A64B1A  lea         ecx,[var1]  
19 00A64B1D  push        ecx  
20 00A64B1E  call        Swap (0A61424h)  
21 00A64B23  add         esp,8 

上面代码再次证明了,引用与指针的行为完全一致,只是编译器在编译时对引用作了更严格的限制。

从汇编代码可以看出实际上指针和引用在编译器中的实现是一样的:

引用int& ref=i;

8048727: 8d 44 24 1c             lea 0x1c(%esp),%eax// esp寄存器里的变量i的地址传给eax

804872b: 89 44 24 18             mov %eax,0x18(%esp)//将寄存器eax中的内容(i的地址)传给寄存器中的变量ref,即int& ref=i

指针int* p=&i;

8048777: 8d 44 24 1c              lea 0x1c(%esp),%eax// esp寄存器里的变量i的地址传给eax

804877b: 89 44 24 10              mov %eax,0x10(%esp) //将寄存器eax中的内容(即i的地址)传到寄存器esp中的p

虽然指针和引用最终在编译中的实现是一样的,但是引用的形式大大方便了使用也更安全。有人说:"引用只是一个别名,不会占内存空间?"通过这个事实我们可以揭穿这个谎言!实际上引用也是占内存空间的。

四、引用占多大的内存空间

因为在在表达式中,使用引用实际上就像使用变量本身一样,所以直接用sizeof是得不到引用本身的大小的。

double var = 42.0; 
double& ref = var;

cout << sizeof var << endl;  // print 8 
cout << sizeof ref << endl;   // print 8

我们可以通过定义一个只含有引用的类来解决这个问题:

1 class refClass{ 
2 private: 
3     double& ref; 
4 public: 
5     refClass(double var = 42.0) :ref(var){} 
6 };
7 
8 cout << sizeof refClass << endl;  // print 4

所以结论就是引用和指针一样实际占内存空间4个字节。

07--C++中引用的本质思考

C++中的复合类型有2个:引用和指针。关于引用的要点包括以下几个方面: 引用是为对象起了另一个名字、别名; 定义引用的表示方法与定义指针相似,只是用&代替了*,&在此不是求地址运算,而是起标识作用; ...

引用的本质是什么?

在大学的时候,教材里这么说的“引用是个别名...引用作为目标的别名而使用...引用不是值不占存储空间...引用只有声明,没有定义...” 那么,引用到底占不占内存空间,引用的本质是什么? 下面举个...

C++中引用的本质

一般的教材上讲到引用时,都是说“引用是对象的一个别名”。我认为这种定义是不清晰的,不利于初学者理解引用。至少我自己曾经被这个定义困扰了一段时间。到底什么是“别名”?     实际上,引用的实质是...

C++ 指针和引用的本质 (一)

先写个最简单的测试代码: test_ref.cpp: #include int main(void) { int a = 10; int &ra = a; ra =20; ...

C++中引用的本质是什么?

C++中引用的本质是什么?

从汇编和高级语言的角度理解传值方式,传值,传引用,传指针的本质机制与区别。白话通俗易懂。

函数的传参与返回值的方式有传值和传递引用,c语言中就是传值,而c++扩展传引用。 而传值分为传递值(实参的值,此时形参是实参在内存中的一份拷贝,形参在使用时分配内存,结束时释放,实参和形参在内存中的...

C++中引用的本质是什么?

一般的教材上讲到引用时,都是说“引用是对象的一个别名”。我认为这种定义是不清晰的,不利于初学者理解引用。至少我自己曾经被这个定义困扰了一段时间。到底什么是“别名”?     实际上,引用的实质是...
  • whkjlcw
  • whkjlcw
  • 2014年04月10日 20:57
  • 446

c++之引用的本质

引用变量是c++引入的重要机制。错误观念:引用本质只是别名,在符号表中ri和i对应于相同的变量地址int i=5; 0100437E mov dword ptr [i],5 ...

C++引用本质

(关于转贴文章的声明,首先感谢原文作者的辛苦努力.如果转贴的文章损害了作者的利益,请与本人联系,本人将会删除相关文章.) 原文在http://www.rayoko.com/article/201.h...
  • B080310
  • B080310
  • 2011年05月07日 14:36
  • 1238

引用的本质是什么?

转载地址:http://www.cnblogs.com/rollenholt/articles/1907408.html 在大学的时候,教材里这么说的“引用是个别名...引用作为目标的别名而使用...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:引用的本质
举报原因:
原因补充:

(最多只允许输入30个字)