C++ 中“空引用”与“空指针”的区别

http://blog.csdn.net/luansxx/article/details/10134139

C++ 中“空引用”与“空指针”的区别

分类: C/C++ 1276人阅读 评论(0) 收藏 举报

网络上有很多讨论C++ 的“引用”与“指针“的区别的文章,谈到区别,其中有一条:“引用不能为空(NULL),引用必须与合法的存储单元关联,指针则可以是NULL)”,但在实际应用中,有时候为了保持一致性,我们会抛开这个规则,人为创造出一个“空引用”。

很多情况下,“空引用”确实可以工作,以致于“引用不能为空”的忠告,被嘲笑为形式主义,仅仅是标准制定者的耸人听闻。一个“空引用”的例子是:

  1. int * a = NULL;  
  2. int & b = *a;  

于是当访问b的时候,程序异常出现了:

  1. void f(int & p)  
  2. {  
  3.     p = 0;  
  4. }  
  5. f(b);  

当然,可以增加点判断,修正这个问题:

  1. void f(int & p)  
  2. {  
  3.     if (&p) p = 0;  
  4. }  

怎么样,是不是有点别扭?但是如果换成成指针,你要输入的字符数是一模一样的:

  1. void f(int * p)  
  2. {  
  3.     if (p) *p = 0;  
  4. }   

 于是,到底是使用“引用”还是“指针”,好像就是智者见智仁者见仁的事情了。

 

然而,然而。。。。。。

 

这真的一样吗?

 

我们来看看复杂一点的例子:

  1. // test.cpp  
  2.   
  3. #include <iostream>  
  4.   
  5. class A  
  6. {  
  7.     int a;  
  8. };  
  9.   
  10. class B  
  11. {  
  12.     int b;  
  13. };  
  14.   
  15. class C  
  16.     : public A, public B  
  17. {  
  18.     int c;  
  19. };  
  20.   
  21. void fb(B & b)  
  22. {  
  23.     std::cout << &b << std::endl;  
  24. }  
  25.   
  26. void fb(B * b)  
  27. {  
  28.     std::cout << b << std::endl;  
  29. }  
  30.   
  31. int main(int argc, char* argv[])  
  32. {  
  33.     C * c = NULL;  
  34.   
  35.     fb(c);  
  36.   
  37.     fb(*c);  
  38.   
  39.     return 0;  
  40. }  

编译运行一下看看:

[plain] view plain copy
  1. $ ./test  
  2. 0  
  3. 0x4  

咦,怎么&b不是0,也就是不是“空引用”了,这时候,即使加上判断,if (&b),也无济于事了。

大家也许注意到了,上面是linux环境运行,那么windows环境呢:

[plain] view plain copy
  1. >test.exe  
  2. 00000000  
  3. 00000000  

这时候,“空引用”保持了他的“空”属性,仅在windows平台做C++的开发者,可以松口气了。

这是怎么回事呢,是你的眼睛欺骗了你?也许是,但是CPU不会欺骗我们,从汇编代码可以看出本质。下面是linux平台编译的代码:

[plain] view plain copy
  1. Dump of assembler code for function main:  
  2.    0x0804870a <+0>:     push   %ebp  
  3.    0x0804870b <+1>:     mov    %esp,%ebp  
  4.    0x0804870d <+3>:     and    $0xfffffff0,%esp  
  5.    0x08048710 <+6>:     sub    $0x20,%esp  
  6.    0x08048713 <+9>:     movl   $0x0,0x1c(%esp)  
  7.    0x0804871b <+17>:    cmpl   $0x0,0x1c(%esp)  
  8.    0x08048720 <+22>:    je     0x804872b <main+33>  
  9.    0x08048722 <+24>:    mov    0x1c(%esp),%eax  
  10.    0x08048726 <+28>:    add    $0x4,%eax  
  11.    0x08048729 <+31>:    jmp    0x8048730 <main+38>  
  12.    0x0804872b <+33>:    mov    $0x0,%eax  
  13.    0x08048730 <+38>:    mov    %eax,(%esp)  
  14.    0x08048733 <+41>:    call   0x80486df <fb(B*)>  
  15.    0x08048738 <+46>:    mov    0x1c(%esp),%eax  
  16.    0x0804873c <+50>:    add    $0x4,%eax  
  17.    0x0804873f <+53>:    mov    %eax,(%esp)  
  18.    0x08048742 <+56>:    call   0x80486b4 <fb(B&)>  
  19.    0x08048747 <+61>:    mov    $0x0,%eax  
  20.    0x0804874c <+66>:    leave    
  21.    0x0804874d <+67>:    ret      

这是windows平台的:

[plain] view plain copy
  1. wmain:  
  2. 004114D0  push        ebp    
  3. 004114D1  mov         ebp,esp   
  4. 004114D3  sub         esp,0DCh   
  5. 004114D9  push        ebx    
  6. 004114DA  push        esi    
  7. 004114DB  push        edi    
  8. 004114DC  lea         edi,[ebp-0DCh]   
  9. 004114E2  mov         ecx,37h   
  10. 004114E7  mov         eax,0CCCCCCCCh   
  11. 004114EC  rep stos    dword ptr es:[edi]   
  12. 004114EE  mov         dword ptr [c],0   
  13. 004114F5  mov         eax,dword ptr [c]   
  14. 004114F8  mov         dword ptr [rc],eax   
  15. 004114FB  cmp         dword ptr [c],0   
  16. 004114FF  je          wmain+3Fh (41150Fh)   
  17. 00411501  mov         eax,dword ptr [c]   
  18. 00411504  add         eax,4   
  19. 00411507  mov         dword ptr [ebp-0DCh],eax   
  20. 0041150D  jmp         wmain+49h (411519h)   
  21. 0041150F  mov         dword ptr [ebp-0DCh],0   
  22. 00411519  mov         ecx,dword ptr [ebp-0DCh]   
  23. 0041151F  push        ecx    
  24. 00411520  call        fb (411118h)   
  25. 00411525  add         esp,4   
  26. 00411528  cmp         dword ptr [rc],0   
  27. 0041152C  je          wmain+6Ch (41153Ch)   
  28. 0041152E  mov         eax,dword ptr [rc]   
  29. 00411531  add         eax,4   
  30. 00411534  mov         dword ptr [ebp-0DCh],eax   
  31. 0041153A  jmp         wmain+76h (411546h)   
  32. 0041153C  mov         dword ptr [ebp-0DCh],0   
  33. 00411546  mov         ecx,dword ptr [ebp-0DCh]   
  34. 0041154C  push        ecx    
  35. 0041154D  call        fb (41108Ch)   
  36. 00411552  add         esp,4   
  37. 00411555  xor         eax,eax   
  38. 00411557  pop         edi    
  39. 00411558  pop         esi    
  40. 00411559  pop         ebx    
  41. 0041155A  add         esp,0DCh   
  42. 00411560  cmp         ebp,esp   
  43. 00411562  call        @ILT+345(__RTC_CheckEsp) (41115Eh)   
  44. 00411567  mov         esp,ebp   
  45. 00411569  pop         ebp    
  46. 0041156A  ret                

汇编代码有兴趣自己研究,不细说了。


回过头想想,两个平台的编译器的两种处理方式,都有他的合理性,windows平台增加了容错性,而linux平台在处理引用时减少判断,增加性能。这隐隐体现出windows与linux开发理念的不同。

最后,请大家记住,引用不能为空,如果可能存在空对象时,请使用指针。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值