工作问题积累(二十)销毁windows对象时,使用DestroyWindow而不是delete C++

来源:互联网 发布:windows上运行mac应用 编辑:程序博客网 时间:2024/06/11 03:17

1.问题

做客户端程序,避免不了与窗口类打交道,昨天就遇到了一个内存释放的问题。代码如下:

class CFriendButton:public CBFCWnd{public:CFriendButton();virtual ~CFriendButton();protected:afx_msg void OnLButtonDown(UINT nFlags, CPoint point);afx_msg void OnSize(UINT nType, int cx, int cy);DECLARE_MESSAGE_MAP()public:void SelectBtn( int nTabPage,BOOL bshow );void SetButtonTitle(CString strTitle);public:intm_nButtonID;COLORREFm_colorHover;COLORREFm_colorSelected;};


 

上面是一个类的定义,最底层的基类还是CWnd,具体函数实现就不写出来了。

vector<CFriendButton *>  m_vetButton每次new 之后调用m_vetButton.push_back()该指针,在析构函数中执行如下代码: for (vector<CRoomButton *>::iterator it = m_vetButton.begin(); it != m_vetButton.end(); it ++) {  if (NULL != *it)  {   delete *it;   *it = NULL;  } } m_vetButton.clear();


 

 直接关闭主窗口时,代码就会报错,这个vector中的指针究竟怎么来释放呢?

 

2.解析

Destroy Window  Objects(销毁窗口对象)如标题所诉,“要销毁一个C++的Windows对象,使用DestroyWindow而不是delete”这个是最重要的规则。

如果你遵照以下的指导方法,你就会很少碰到清除方面的问题(例如忘记删除/释放C++内存,忘记释放系统资源比如说HWNDS,或者释放对象太多次),我们必须提供一组规则以防止系统资源或者应用程序的内存泄露问题,同时也防止对象和windows句柄被多次销毁。

销毁窗口:

有两种方法被允许来销毁一个windows对象:

(1.)调用CWnd::DestroyWindow或者Windows API::DestroyWindow.

(2.)利用delete操作符来进行明确的删除操作。

第一种方法是迄今为止最常用的。即使DestroyWindow没有在你的代码里被直接调用,此方法也照常适用。这种情况就是,当用户直接关闭一个框架窗口时(缺省的WM_CLOSE行为主动调用DestroyWindow),当一个父窗口(框架窗口)被销毁时,windows会调用DestroyWindow来销毁它的所有的子窗口。

利用CWnd::PostNcDestroy进行自动清除,当销毁一个windows窗口时,最后发送给此窗口的windows消息是WM_NCDESTROY。CWnd对此消息的缺省处理(CWnd::OnNcDestroy)会将C++对象与HWND分离,并调用虚函数PostNcDestroy。一些类重载这个函数来删除C++对象。

CWnd::PostNcDestroy的缺省操作是什么也不做,这适合于那些分配在堆栈或者嵌在其他对象里面的窗口对象。这不适用于那些分配在堆上的窗口对象(不嵌在其他C++对象中)。

 

那些设计来分配在堆上的类可以重载成员函数PostNcDestroy以执行“delete this”操作。它将会释放任何与此C++对象相关的C++内存。尽管缺省的CWnd析构函数会在m_hwnd不为空的情况下调用DestroyWindow,但这不会导致无穷递归,因为此句柄在清除阶段将会处于分离状态并为空。

void CBFCWnd::PostNcDestroy(){TRACE(_T("PostNcDestroy\r\n"));if (m_pWndManager){m_pWndManager->DeletedWnd(this);m_pWndManager = NULL;}if (m_nAutoDelete)delete this;//将物理内存的占用挪到虚拟内存里::SetProcessWorkingSetSize(::GetCurrentProcess(), -1, -1);}


 

注意:CWnd::PostNcDestroy一般会在windows消息WM_NCDESTROY处理后被调用,把它作为窗口销毁的一部分,同时HWND和C++窗口对象不再关联。

 

如果你直接使用操作符delete,MFC的诊断内存分配算符将会警告你:你正在第二次释放内存(第一次调用delete,还有在PostNcDestroy的自动清理中执行过程中调用delete this)。

for (int i=0;i<m_vetButton.size();++i){delete m_vetButton[i];}



 

 

0 0