用汇编的眼光看C++(之delete内存泄露)21
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
有过C语言编程的朋友大多知道,如果在malloc内存之后不及时free掉内存,那么很有可能会造成内存泄露的。那么在C++上面,是不是也存在这样 的问题呢?结果是C++上面同样也存在内存泄露的危险。这个危险就是如果new后面不能delete的话,也会造成内存的泄露。还有不清楚的朋友可以看看 下面的示例:
- class test
- {
- int data;
- public:
- test(int value):data(value) {}
- ~test() {};
- };
- void process()
- {
- test* t = new test(0);
- if(/* some errors happens */)
- {
- return;
- }
- delete t;
- return;
- }
上面的代码在一定程度上说明了问题。其实上面这段代码在函数返回的时候已经考虑到了内存删除的问题,但是关键是如果在error发生的时候,没有及时处 理的话也会造成内存泄露的。那么有没有什么好的方法呢?大家可以看看C++有没有什么性质可以保证函数在结束的时候可以自动完成资源的释放。对,那就是析 构函数。所以,一般的话我们可以添加一个额外的类定义。
- class auto_point
- {
- test* t;
- public:
- auto_point(test* p) : t(p) {}
- ~auto_point() { if(t) delete t;}
- };
但是,原来我们的好多操作都是按照指针进行的,那么怎么把类转变成指针呢?那就只有使用算术符重载了。
- class auto_point
- {
- test* t;
- public:
- auto_point(test* p) : t(p) {}
- ~auto_point() { if(t) delete t;}
- test* operator->() { return t;}
- const test& operator* () {return *t;}
- };
那么有了这样的一个定义之后,我们应该怎么使用呢?大家可以看看下面的函数调用:
- 22: auto_point p(new test(0));
- 004010AD push 4
- 004010AF call operator new (00401300)
- 004010B4 add esp,4
- 004010B7 mov dword ptr [ebp-18h],eax
- 004010BA mov dword ptr [ebp-4],0
- 004010C1 cmp dword ptr [ebp-18h],0
- 004010C5 je process+56h (004010d6)
- 004010C7 push 0
- 004010C9 mov ecx,dword ptr [ebp-18h]
- 004010CC call @ILT+80(test::test) (00401055)
- 004010D1 mov dword ptr [ebp-1Ch],eax
- 004010D4 jmp process+5Dh (004010dd)
- 004010D6 mov dword ptr [ebp-1Ch],0
- 004010DD mov eax,dword ptr [ebp-1Ch]
- 004010E0 mov dword ptr [ebp-14h],eax
- 004010E3 mov dword ptr [ebp-4],0FFFFFFFFh
- 004010EA mov ecx,dword ptr [ebp-14h]
- 004010ED push ecx
- 004010EE lea ecx,[ebp-10h]
- 004010F1 call @ILT+65(auto_point::auto_point) (00401046)
- 004010F6 mov dword ptr [ebp-4],1
- 23: if(1/* some errors happens */)
- 004010FD mov edx,1
- 00401102 test edx,edx
- 00401104 je process+97h (00401117)
- 24: {
- 25: return;
- 00401106 mov dword ptr [ebp-4],0FFFFFFFFh
- 0040110D lea ecx,[ebp-10h]
- 00401110 call @ILT+75(auto_point::~auto_point) (00401050)
- 00401115 jmp process+0A6h (00401126)
- 26: }
- 27:
- 28: return;
- 00401117 mov dword ptr [ebp-4],0FFFFFFFFh
- 0040111E lea ecx,[ebp-10h]
- 00401121 call @ILT+75(auto_point::~auto_point) (00401050)
- 29: }
大家可以从上面的代码看得很清楚,不管代码在什么时候退出,函数都会利用类的基本特性,自动调用类的析构函数,那么进而内存就会得到释放,不会发生内存 泄露的问题。但是我们发现上面的解决方案也有不足的地方,就是每一个类都需要额外定义一个额外的定义类。那么有没有什么办法解决这一问题呢?那就是模板 了。
- template <typename type>
- class auto_point
- {
- type* t;
- public:
- auto_point(type* p) : t(p) {}
- ~auto_point() { if(t) delete t;}
- test* operator->() { return t;}
- const test& operator* () {return *t;}
- };
如果我们的类型不是特定的,那么我们只需要在使用的时候按照特定的类型输入即可。
【预告: 下面的一篇博客会介绍类成员指针拷贝的问题】