今天遇到一个很诡异的内存泄露,记录如下:
1.两个类,记为A,B。其中A有应指向B的指针;B也有指针成员,指向new出来的空间。两个类定义如下:
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><pre name="code" class="cpp">1.1文件A.h
class B;
class A{public:
~A();
public:
B * m_pB;
...
};
1.2 文件A.cpp
#include "A.h"
A::~A()
{
if(m_pB)
{
delete m_pB;
m_pB = NULL;
}
}
1.3 文件B.h
<pre name="code" class="cpp"><pre name="code" class="cpp">class B{
public:
B();
~B();
private:
int * m_p0;
...
};
1.4 文件B.cpp
#include "B.h"
B::B()
{
m_p0 = new int(NUM);
}
B::~B()
{
if(m_p0)
{
delete m_p0;
m_p0 = NULL;
}
}
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">根据上述定义,可以看出:</span>
1)B类里有new的指针,因此需要自定义析构函数,否则会造成内存泄露;
2)A类中有B的指针(下面会用new来赋值),但A.h文件只是声明了B类,而不是包含B类的头文件。A.cpp文件也未包含B.h,因此也是看不到B类的定义的。
2.下面给出main函数:
</pre><pre name="code" class="cpp">#include "A.h"
#include "B.h"
int main()
{
A * pA = new A;
A.m_pB = new B();
delete pA;
}
3.分析:
理论上说,执行delete pA;会调用A的析构函数,而A的析构函数又会调用B的析构函数,B的析构函数析构new出来的数组空间。然而实际上并非如此,上述代码会造成内存泄露。原因如下:
执行delete pA;会调用A类的析构函数,这步没有错。A类的析构函数会执行delete m_pB; 这步并不会调用B类的析构函数,原因在于A类的析构函数看不到B类的定义,所以也就不知道B类定义了自己的析构函数,它只释放了B类占用的空间(不包括B类里m_p0指针指向的空间)。因此造成内存泄露。
解决方法很简单:在A.cpp中包含头文件B.h。
4.总结:
这个代码是在VS2010里写的,我不确定上述问题是C++语法的问题,还是VS的问题。有上面的分析我搞明白了delete所做的工作,delete一个指针p,p指向的对象的大小size肯定是知道的,那么delete的功能就是释放从p开始,大小为size的连线空间。