C++MFC学习心得(三)——PostNcDestroy,~MainWnd(),OnDestroy(),~CWinApp()的区别。。。
2013-05-18 13:40
831 查看
今天,继续学习中,不过遇到若干内存泄漏的问题。
先说说程序构成吧,一个***的继承自CListBox的类COwnerDrawListBox。
直接先贴代码。。。
下面是析构的东西。。。
好了,代码贴完,开始分析。。。
因为是手写,刚开始自己写的OnPaint(){},里面没有任何东西的时候,CPU直接满载,刚开始以为是控件重画导致的,可是,直到注释掉所有的代码,才发现是OnPaint的问题,最后查了一下,是OnPaint里必须至少要有一个CPaintDC的操作,原因很简单,就是没有这样的操作,系统默认没画过,ON_WM_PAINT消息一直存在,无限循环跟while(1)差不多,以后必须注意。
后来,想用这个***列表框来存储文字,比如现实你存进去的文字啦什么的。这次,当然失败了。。。
原来用的以下代码:
m_wndCODL.AddString(_T("Hello"));
然后在OnDrawItem中加入如下代码:
m_wndCODL.GetText(nIndex,str);
dc.TextOut(rect.left,rect.top,str);
这时候输出乱码,我以为是数据形式的问题,就各种换,但是不行,于是只好单步。
但不之后发现,AddString之后,AddString,对于不同的数值敏感,但是,数值一样,输出也一样。。
这时已经出现了Cwnd Object泄漏了。。。
这时我就想到可能是重画的原因了,去掉重画,直接Pass,这说明,开启重画之后,AddString加入的值并不是字符串了。查了一下,然后看了一下CListBox里的类函数,看到了SetItemData,稍微测试了一下证明了我的猜想。。。
好吧,接下来,SetItemData的参数为DWORD_PTR类型,即_w64 unsigned long,大小四字节,为什么是4字节?代码如下:
这时候,我就明白这个DWORD_PTR的意思了,就是让你存指针用的。。。果断申请内存,CString* pStr = new CString;然后,显示,可以了。。。
泄漏问题正式开始,前文已经提到,在错误结果的时候,出现了CWnd Object泄漏,我就知道是MainWnd没有析构。。。可是怎么会出现这个呢?首先想到的是,CWinApp,因为只有CWinApp中又new CMainWnd这一句。。。然后析构,delete m_MainWnd;果断失败,不明白为什么。。。于是看了之前的例程一下,哦~~应该加个PostNcDestroy();
加上delete this,成功。。。
肯定还有失败的,那就是自己申请的那一部分内存,习惯性的加入到PostNcDestroy()中,失败,而且又出现了,CWnd Object泄漏。这下单步,看到根本没有运行delete this。。。出问题了。。。而是在删除我自己申请的内存的时候直接跳出循环的。。。感觉PostNcDestroy()只能删除一次?事实不是如此,而是,在OnDestroy之后,就已经没有控件在内存中了,所以delete出错了。。。返回值为3。。
这次,想到还有个OnDestroy 没用,在这里删除,成功了。。。这下我就想知道这几个函数之间的关系了。。。
全加断点,然后运行,可以看出时间顺序。。。
首先,OnDestroy,最开始的,接受到ON_WN_DESTROY,调用这里,所以,这里释放一些用户内存是很好的。在这里,给用户释放的时间。
然后PostNcDestroy,释放用户视图,然后把自己析构掉。。。释放视图对象,因为这时候视图已经关掉了。
再就是,PostNcDestroy中的delete this,调用的~CMainWnd(),为什么不在这里释放用户内存?因为在窗口消失的那一瞬间(不是隐藏窗口),视图句柄都已经为0了,这个过程是在OnDestroy之前,但是一些全局内存仍然可以释放。
最后,就是~CMyApp(),释放掉进程,彻底关闭。
先说说程序构成吧,一个***的继承自CListBox的类COwnerDrawListBox。
BOOL COwnerDrawListBox::PreCreateWindow(CREATESTRUCT& cs) { if(!CListBox::PreCreateWindow(cs)) return FALSE; cs.style &= -(LBS_OWNERDRAWVARIABLE|LBS_SORT); cs.style |= LBS_OWNERDRAWFIXED; return TRUE; } void COwnerDrawListBox::MeasureItem(LPMEASUREITEMSTRUCT lpmis) { lpmis->itemHeight = 32; } void COwnerDrawListBox::DrawItem(LPDRAWITEMSTRUCT lpdis) { CDC dc; dc.Attach(lpdis->hDC); CRect rect = lpdis->rcItem; UINT nIndex = lpdis->itemID; CBrush* pBrush = new CBrush( ::GetSysColor((lpdis->itemState&ODS_SELECTED)?COLOR_HIGHLIGHT:COLOR_WINDOW) ); dc.FillRect(rect,pBrush); delete pBrush; dc.SelectObject(&FontGlob); if(nIndex!=(UINT)-1) { dc.SetBkMode(TRANSPARENT); CString str; GetItemData(nIndex); dc.TextOut(rect.left,rect.top,*((CString*)GetItemData(nIndex))); } dc.Detach(); } int CMainWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CWnd::OnCreate(lpCreateStruct) == -1) return -1; FontGlob.CreatePointFont(240,"Arial"); CClientDC dc(this); TEXTMETRIC tm; dc.GetTextMetrics(&tm); m_cxChar = tm.tmAveCharWidth; m_cyChar = tm.tmHeight + tm.tmExternalLeading; CRect rect( m_cxChar*2, m_cyChar*1, m_cxChar*40, m_cyChar*10); // TODO: 在此添加您专用的创建代码 m_wndCNumEdit.Create(WS_CHILD|WS_VISIBLE|WS_VSCROLL|ES_MULTILINE|ES_AUTOVSCROLL|WS_BORDER|ES_WANTRETURN,rect,this,IDC_CNUMEDIT); rect.SetRect(m_cxChar*2, m_cyChar*11, m_cxChar*40, m_cyChar*20); m_wndCODL.Create(WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_BORDER,rect,this,IDC_CODLB); for(int i = 0;i<10;i++) { CString* pStr = new CString; pStr->Format(_T("%d"),i); m_wndCODL.AddString(_T("")); m_wndCODL.SetItemData(i,(DWORD)pStr); } return 0; }
直接先贴代码。。。
下面是析构的东西。。。
void CMainWnd::PostNcDestroy() { // TODO: 在此添加专用代码和/或调用基类 delete this; } CMainWnd::~CMainWnd() { CWnd::~CWnd(); } void CMainWnd::OnDestroy() { for(int i = 0;i<m_wndCODL.GetCount();i++) { delete (CString*)m_wndCODL.GetItemData(i); } CWnd::OnDestroy(); // TODO: 在此处添加消息处理程序代码 }
好了,代码贴完,开始分析。。。
因为是手写,刚开始自己写的OnPaint(){},里面没有任何东西的时候,CPU直接满载,刚开始以为是控件重画导致的,可是,直到注释掉所有的代码,才发现是OnPaint的问题,最后查了一下,是OnPaint里必须至少要有一个CPaintDC的操作,原因很简单,就是没有这样的操作,系统默认没画过,ON_WM_PAINT消息一直存在,无限循环跟while(1)差不多,以后必须注意。
后来,想用这个***列表框来存储文字,比如现实你存进去的文字啦什么的。这次,当然失败了。。。
原来用的以下代码:
m_wndCODL.AddString(_T("Hello"));
然后在OnDrawItem中加入如下代码:
m_wndCODL.GetText(nIndex,str);
dc.TextOut(rect.left,rect.top,str);
这时候输出乱码,我以为是数据形式的问题,就各种换,但是不行,于是只好单步。
但不之后发现,AddString之后,AddString,对于不同的数值敏感,但是,数值一样,输出也一样。。
这时已经出现了Cwnd Object泄漏了。。。
这时我就想到可能是重画的原因了,去掉重画,直接Pass,这说明,开启重画之后,AddString加入的值并不是字符串了。查了一下,然后看了一下CListBox里的类函数,看到了SetItemData,稍微测试了一下证明了我的猜想。。。
好吧,接下来,SetItemData的参数为DWORD_PTR类型,即_w64 unsigned long,大小四字节,为什么是4字节?代码如下:
#if defined(_WIN64) typedef __int64 INT_PTR, *PINT_PTR; typedef unsigned __int64 UINT_PTR, *PUINT_PTR; typedef __int64 LONG_PTR, *PLONG_PTR; typedef unsigned __int64 ULONG_PTR, *PULONG_PTR; #define __int3264 __int64 #else typedef _W64 int INT_PTR, *PINT_PTR; typedef _W64 unsigned int UINT_PTR, *PUINT_PTR; typedef _W64 long LONG_PTR, *PLONG_PTR; typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR; #define __int3264 __int32 #endif
这时候,我就明白这个DWORD_PTR的意思了,就是让你存指针用的。。。果断申请内存,CString* pStr = new CString;然后,显示,可以了。。。
泄漏问题正式开始,前文已经提到,在错误结果的时候,出现了CWnd Object泄漏,我就知道是MainWnd没有析构。。。可是怎么会出现这个呢?首先想到的是,CWinApp,因为只有CWinApp中又new CMainWnd这一句。。。然后析构,delete m_MainWnd;果断失败,不明白为什么。。。于是看了之前的例程一下,哦~~应该加个PostNcDestroy();
加上delete this,成功。。。
肯定还有失败的,那就是自己申请的那一部分内存,习惯性的加入到PostNcDestroy()中,失败,而且又出现了,CWnd Object泄漏。这下单步,看到根本没有运行delete this。。。出问题了。。。而是在删除我自己申请的内存的时候直接跳出循环的。。。感觉PostNcDestroy()只能删除一次?事实不是如此,而是,在OnDestroy之后,就已经没有控件在内存中了,所以delete出错了。。。返回值为3。。
这次,想到还有个OnDestroy 没用,在这里删除,成功了。。。这下我就想知道这几个函数之间的关系了。。。
void CMainWnd::PostNcDestroy() { // TODO: 在此添加专用代码和/或调用基类 delete this; } CMainWnd::~CMainWnd() { CWnd::~CWnd(); } void CMainWnd::OnDestroy() { for(int i = 0;i<m_wndCODL.GetCount();i++) { delete (CString*)m_wndCODL.GetItemData(i); } CWnd::OnDestroy(); // TODO: 在此处添加消息处理程序代码 }CMyApp::~CMyApp()
{
delete m_pMainWnd;
}
全加断点,然后运行,可以看出时间顺序。。。
首先,OnDestroy,最开始的,接受到ON_WN_DESTROY,调用这里,所以,这里释放一些用户内存是很好的。在这里,给用户释放的时间。
然后PostNcDestroy,释放用户视图,然后把自己析构掉。。。释放视图对象,因为这时候视图已经关掉了。
再就是,PostNcDestroy中的delete this,调用的~CMainWnd(),为什么不在这里释放用户内存?因为在窗口消失的那一瞬间(不是隐藏窗口),视图句柄都已经为0了,这个过程是在OnDestroy之前,但是一些全局内存仍然可以释放。
最后,就是~CMyApp(),释放掉进程,彻底关闭。
相关文章推荐
- C++ MFC学习心得(一)
- C++MFC学习心得(五)——单文档视图结构分析
- C++MFC学习心得(四)——CListBox自绘控件碰到的一个小问题
- C++ MFC学习心得(二)
- C++学习心得--类
- VC学习笔记---ATL MFC CLR三个库的区别
- C++学习心得
- C++、VC++、MFC区别和联系
- C++学习心得(5)继承与派生
- 《More Effective C++》学习心得(六)各种new和delete操作符
- 2013级大一下学期学习c++心得
- MFC CTreeView学习之右键菜单_获取选中节点的方式HitTest和GetSelectedItem的区别(二)
- 学习C++心得与值得一看的书
- C++学习心得
- VS2013MFC对话框工程学习笔记六 - 了解C++的数据类型
- C++指针学习心得(一)
- C++用法的学习心得
- <C++学习笔记>引用中的&和&&区别
- C++用法的学习心得
- C++学习心得体会