最近项目出现内存泄漏的问题,找到非模态对话框的指针释放问题,尤其是很多层对话框的释放问题。
每个CPP文件加上:
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
这段代码会检测到new出来的指针,没有释放的内存泄漏。
关于非模态对话框的指针释放的问题,找了一些资料,总结如下:就是父子对话框的时候,父对话框用指针创建一个对话框:
父对话框里
定义:Cdialog1* m_dialog1;//Cdialog1*是子对话框的类
创建并显示:
m_dialog1 = new Cdialog1();
m_dialog1->Create(IDD_DIALOG1 ,this);
m_dialog1->ShowWindow(SW_SHOW);
那究竟在哪里释放m_dialog1 比较合理呢?
这里面要明白窗口的一些机制,每一个窗口关闭的时候(用CDialog::OnOk()或者CDialog::OnCancel()),只是隐藏了窗口而已,并没有销毁窗口。所以窗口还会执行CDialog::OnDestroy()销毁窗口,一旦执行完这个,窗口的句柄就会m_Hwnd=NULL,最后才是执行析构函数。窗口的关闭和销毁过程是这样的一个顺序。
不信拉一个窗口出来试试就知道了。
可是,子窗口是在父窗口用m_dialog1 = new Cdialog1()出来的,指针对象是在Heap(堆)的,一定要释放,不然内存泄漏,虽然窗口句柄在关闭整个程序的时候,会自动从父窗口—子窗口的顺序OnDestory(),可是指针对象不会自动就销毁了。简而言之,就是句柄没有了,窗口指针对象还在(句柄只是指针的众多数据里的一员)。
可是,在哪里释放才是合适合理的呢。
测试1:
在子对话框里面OnDestory()主动调用delete this,释放对象,delete this会触发析构函数,看起来顺序似乎和上面说到的销毁窗口的机制一样,可是就会报出错误:
Warning: calling DestroyWindow in CDialog::~CDialog --OnDestroy or PostNcDestroy in derived class will not be called.
原因是:OnDestory函数要执行完返回才会销毁句柄,如果没有执行完就去delete this,会触发析构函数,进入析构函数前没有销毁窗口就会报这样的警告。
测试2:我们在父窗口里释放指针对象,因为我们是在这里new出来的,在这里delete才对。
这里注意到,基于对话框的程序主窗口是没有析构函数的,自己加上会报错,原因不明。
CtestptDlg是主对话框的类,所以这里放在OnDesotry()执行销毁下一级窗口和释放指针。
void CteseptDlg::OnDestroy()
{
CDialogEx::OnDestroy();
// TODO: 在此处添加消息处理程序代码
if (m_dialog1 != NULL)
{
m_dialog1->DestroyWindow();
HWND hmydialog1 = m_dialog1->GetSafeHwnd(); //这里子对话框句柄肯定没有了,看上一句
delete m_dialog1;
//m_dialog1 = NULL;//这样 = delete
}
除了主窗口比较特殊,其他的窗口释放都应该放在析构里面 。
Cdialog1::~Cdialog1()
{
if (pdialog2 != NULL)
{
pdialog2->DestroyWindow();//这里如果还有下一级子对话框,会自动往下一级destory
HWND hmydialog1 = pdialog2->GetSafeHwnd(); //这里子对话框句柄肯定没有了,看上一句
delete pdialog2;
//m_dialog1 = NULL;//这样 = delete
}
}
pdialog2是Cdialog下一级的对话框,如果我们一下关闭了整个主窗口,执行pdialog2->DestroyWindow()前已经执行过一次了,这里再写一次的话,实际是执行不成功的,返回FALSE。不过为了写法统一,还是这样写吧。这里说明窗口可以重复DestoryWindow(),可是指针不能重复delete。
还有一些东西,如果在类中要delete自己对象呢?这里最好发送消息给父窗口,来执行销毁自己和释放指针,而不要自己在类里面delete this ,除非你的类是单模式的。