从汇编的眼光看C++(之delete内存泄露)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/feixiaoxing/article/details/6823809

【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】


    有过C语言编程的朋友大多知道,如果在malloc内存之后不及时free掉内存,那么很有可能会造成内存泄露的。那么在C++上面,是不是也存在这样的问题呢?结果是C++上面同样也存在内存泄露的危险。这个危险就是如果new后面不能delete的话,也会造成内存的泄露。还有不清楚的朋友可以看看下面的示例:


 
 
  1. class test
  2. {
  3. int data;
  4. public:
  5. test( int value):data( value) {}
  6. ~test() {};
  7. };
  8. void process()
  9. {
  10. test* t = new test( 0);
  11. if( /* some errors happens */)
  12. {
  13. return;
  14. }
  15. delete t;
  16. return;
  17. }
    上面的代码在一定程度上说明了问题。其实上面这段代码在函数返回的时候已经考虑到了内存删除的问题,但是关键是如果在error发生的时候,没有及时处理的话也会造成内存泄露的。那么有没有什么好的方法呢?大家可以看看C++有没有什么性质可以保证函数在结束的时候可以自动完成资源的释放。对,那就是析构函数。所以,一般的话我们可以添加一个额外的类定义。


 
 
  1. class auto_point
  2. {
  3. test* t;
  4. public:
  5. auto_point(test* p) : t(p) {}
  6. ~auto_point() { if(t) delete t;}
  7. };
    但是,原来我们的好多操作都是按照指针进行的,那么怎么把类转变成指针呢?那就只有使用算术符重载了。


 
 
  1. class auto_point
  2. {
  3. test* t;
  4. public:
  5. auto_point(test* p) : t(p) {}
  6. ~auto_point() { if(t) delete t;}
  7. test* operator->() { return t;}
  8. const test& operator* () { return *t;}
  9. };

    那么有了这样的一个定义之后,我们应该怎么使用呢?大家可以看看下面的函数调用:


 
 
  1. 22: auto_point p(new test(0));
  2. 004010AD push 4
  3. 004010AF call operator new ( 00401300)
  4. 004010B4 add esp, 4
  5. 004010B7 mov dword ptr [ebp -18h],eax
  6. 004010BA mov dword ptr [ebp -4], 0
  7. 004010C1 cmp dword ptr [ebp -18h], 0
  8. 004010C5 je process+ 56h ( 004010d6)
  9. 004010C7 push 0
  10. 004010C9 mov ecx,dword ptr [ebp -18h]
  11. 004010CC call @ILT+ 80( test:: test) ( 00401055)
  12. 004010D1 mov dword ptr [ebp -1Ch],eax
  13. 004010D4 jmp process+ 5Dh ( 004010dd)
  14. 004010D6 mov dword ptr [ebp -1Ch], 0
  15. 004010DD mov eax,dword ptr [ebp -1Ch]
  16. 004010E0 mov dword ptr [ebp -14h],eax
  17. 004010E3 mov dword ptr [ebp -4], 0FFFFFFFFh
  18. 004010EA mov ecx,dword ptr [ebp -14h]
  19. 004010ED push ecx
  20. 004010EE lea ecx,[ebp -10h]
  21. 004010F1 call @ILT+ 65(auto_point::auto_point) ( 00401046)
  22. 004010F6 mov dword ptr [ebp -4], 1
  23. 23: if( 1 /* some errors happens */)
  24. 004010FD mov edx, 1
  25. 00401102 test edx,edx
  26. 00401104 je process+ 97h ( 00401117)
  27. 24: {
  28. 25: return;
  29. 00401106 mov dword ptr [ebp-4],0FFFFFFFFh
  30. 0040110D lea ecx,[ebp-10h]
  31. 00401110 call @ILT+ 75(auto_point::~auto_point) ( 00401050)
  32. 00401115 jmp process+ 0A6h ( 00401126)
  33. 26: }
  34. 27:
  35. 28: return;
  36. 00401117 mov dword ptr [ebp-4],0FFFFFFFFh
  37. 0040111E lea ecx,[ebp-10h]
  38. 00401121 call @ILT+ 75(auto_point::~auto_point) ( 00401050)
  39. 29: }
    大家可以从上面的代码看得很清楚,不管代码在什么时候退出,函数都会利用类的基本特性,自动调用类的析构函数,那么进而内存就会得到释放,不会发生内存泄露的问题。但是我们发现上面的解决方案也有不足的地方,就是每一个类都需要额外定义一个额外的定义类。那么有没有什么办法解决这一问题呢?那就是模板了。


 
 
  1. template < typename type>
  2. class auto_point
  3. {
  4. type* t;
  5. public:
  6. auto_point(type* p) : t(p) {}
  7. ~auto_point() { if(t) delete t;}
  8. test* operator->() { return t;}
  9. const test& operator* () { return *t;}
  10. };
    如果我们的类型不是特定的,那么我们只需要在使用的时候按照特定的类型输入即可。



【预告: 下面的一篇博客会介绍类成员指针拷贝的问题】


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值