第一次用VC++做项目,遇到过很多问题,尤其是内存方面的申请和释放的,这类问题是必须要解决的,但是呢,对于一直做C#开发的我来说,找到问题的原因确实费了太多的时间。前车之鉴不可不牢记,在此让这些问题都烙下深深的痕迹!
1.内存泄漏
项目写到一半的时候,输出窗口显示一大片的内存泄漏,找了一大批内存泄漏的查看工具,全部无果而终。把每个类从头至尾都检查了一遍,每个指针变量在申请之前赋了空值,然后在每个类的析构函数里面都释放了空间,并且把指针又赋为NULL。到这一步发现内存泄漏少了一部分,但是还是有刺眼的一大片!苦了小女子再一次一遍遍的找啊,在网上查啊,无奈没有其他发现。苦苦冥思了几个日日夜夜,突然一天开窍,发现类的成员指针变量每次在申请空间之前并没有判断是不是原来已经有空间,如果已经申请空间,那么再次申请岂不是原来的内存空间就不翼而飞了?这样不就是内存泄漏了么!狂喜之中改了一个模块,测试之后,果真问题解决!幸福!!唉~~ 有了自动回收机制的.net,思维方式根本就不在动态申请内存,自己释放内存这里转了,所以刚开始写VC++代码的时候,根本没有这样的潜意识去管理重复申请的内存!
关于指针内存问题做此总结:
(1)哪里申请,哪里释放!
(2)指针初始化和释放内存后,一定要赋空值!(否则就成野指针)
(3)重新申请空间之前,一定要释放原来的内存!
(4)能不用指针就不用指针,比如:能用数组替代的绝不用指针,可以用引用的绝不用指针!
(5)对于结构体类型的指针,如果结构体里面还有指针,在释放前要先释放结构体的指针成员,再释放结构体指针!
2.堆被损坏(dbgheap.c _CrtIsValidHeapPointer)
堆被损坏这个问题也是头疼得厉害的问题,不好找到出错的位置!
讲到堆被损坏的问题解决方案之前,需要提下程序内存分配的常识:
详细内容见:http://baike.baidu.com/view/93201.htm
一个由C/C++编译的程序占用的内存分为以下几个部分
(1)栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
(2)堆区(heap)— 由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
(3)全局区(静态区)(static)— 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。
(4)文字常量区 — 常量字符串就是放在这里的,程序结束后由系统释放 。
(5)程序代码区— 存放函数体的二进制代码。 所以堆被损坏,那就一般是自己定义什么动态分配内存的变量在使用的时候越界了!一般都是在释放内存的时候出现这个问题,那就检查被释放内存的指针,看看它的空间申请的是多大,然后再查找它在哪些地方使用了,是不是越界了! 3.CListCtrl的继承类 List在MFC项目中的使用非常广泛,但是呢有太多的功能它都没有实现,就需要自己去继承它来完成,比如ListCtrl可编辑功能,更新ListCtrl的单元格颜色,单元格背景!这些都是我的项目中需要实现的。网上资料都很多,我只记录思想。 (1)ListCtrl的可编辑功能,让ListCtrl的单元格可以像编辑框那样输入:捕获OnClick事件,确定当前的单元格位置,获取单元格的矩形范围,在此单元格的位置创建一个编辑框,当编辑框失去焦点的时候,取出编辑框的内容,设置该单元格的文本,然后销毁编辑框。(其他控件同理) (2)设置ListCtrl的单元格颜色,要设置ListCtrl的单元格颜色,就要自绘,网上有很多资料介绍用onCustomerDraw,我试了没有成功!我采用的解决方案是:http://topic.csdn.net/t/20051215/15/4461308.html (3)设置单元格颜色,要自绘,调用DrawItem函数,而DrawItem函数要被调用的前提就是要设置ListCtrl的样式为LVS_OWNERDRAWFIXED ,这样一来就影响另一些功能:ListCtrl要显示CheckBox,选中的行要用颜色高亮显示,这些都没得了!原来自绘就是所有的都要自己绘! 选中行要高亮显示,这个比较简单,只要在DrawItem里面判断ListCtrl是不是设置了扩展样式LVS_EX_FULLROWSELECT,当前行是否被选中就可以了: 1 COLORREF rgbBkgnd;//背景色 2 CRect rcItem(lpDIS->rcItem); //当前行的矩形框 3 if((this->GetExtendedStyle() & LVS_EX_FULLROWSELECT) == LVS_EX_FULLROWSELECT)//判断是否设置了选中行高亮显示的属性 4 { 5 bSelected = (rcItem.PtInRect(m_point) == TRUE); //判断当前行是否被选中 6 if (bSelected) 7 rgbBkgnd = ::GetSysColor(COLOR_HIGHLIGHT);//选中,高亮显示 8 else 9 rgbBkgnd = ::GetSysColor(COLOR_WINDOW);//未选中,系统默认色 10 CBrush br(rgbBkgnd);//背景刷 11 pDC->FillRect(rcItem, &br); //绘制选中行的颜色 12 }
CheckBox的显示:
1)定义一个结构体,标记每个checkBox的状态
1 typedef struct Item_CheckBox 2 { 3 int iItem;//第几行 4 int iState;//选中状态:0-未选中,1-选中,-1-置灰 5 };2)在继承类中添加成员变量:CList<Item_CheckBox*,Item_CheckBox*> m_CheckItem;//保存所有CheckBox的状态
3)重写InsertItem方法:
1 //增加行 2 int CListEditableCtrl::InsertItem(int nItem, LPCTSTR lpszItem) 3 { 4 CListCtrl::InsertItem(nItem,lpszItem); 5 if(((this->GetExtendedStyle() & LVS_EX_CHECKBOXES) == LVS_EX_CHECKBOXES))//设置了CListCtrl的样式有CheckBox 6 { 7 Item_CheckBox *chkItem=new Item_CheckBox; 8 chkItem->iItem=nItem; 9 chkItem->iState=0; 10 m_CheckItem.AddTail(chkItem); 11 } 12 return 0; 13 }4)重写OnLButtonDown事件:
1 void CListEditableCtrl::OnLButtonDown(UINT nFlags, CPoint point) 2 { 3 if (GetFocus() != this) 4 SetFocus(); 5 m_nCurItem =HitTestEx(point,&m_nCurCol); 6 if(this->m_nCurCol==0 && m_CheckItem.GetCount()>0) 7 { 8 POSITION pos=m_CheckItem.FindIndex(m_nCurItem); 9 if(pos!=NULL) 10 { 11 Item_CheckBox *chkItem=m_CheckItem.GetAt(pos); 12 switch(chkItem->iState) 13 { 14 case 0: 15 chkItem->iState=1; 16 break; 17 case 1: 18 chkItem->iState=0; 19 break; 20 default:break; 21 } 22 } 23 } 24 CListCtrl::OnLButtonDown(nFlags, point); 25 }5)在DrawItem中添加如下实现:
1 if(((this->GetExtendedStyle() & LVS_EX_CHECKBOXES) == LVS_EX_CHECKBOXES)) 2 { 3 if(m_CheckItem.GetCount()>0) 4 { 5 Item_CheckBox *chkItem=m_CheckItem.GetAt(m_CheckItem.FindIndex(lpDIS->itemID)); 6 switch(chkItem->iState) 7 { 8 case 0: //未选 9 pDC->DrawFrameControl(CRect(rcItem.left+5,rcItem.top+2,rcItem.left+25,rcItem.bottom-2),DFC_BUTTON,DFCS_BUTTONCHECK); 10 break; 11 case 1://选中 12 pDC->DrawFrameControl(CRect(rcItem.left+5,rcItem.top+2,rcItem.left+25,rcItem.bottom-2),DFC_BUTTON,DFCS_CHECKED); 13 break; 14 case -1://置灰 15 pDC->DrawFrameControl(CRect(rcItem.left+5,rcItem.top+2,rcItem.left+25,rcItem.bottom-2),DFC_BUTTON,DFCS_INACTIVE); 16 break; 17 default: 18 break; 19 } 20 } 21 } 22 for(int nCol=0;nCol<GetHeaderCtrl()->GetItemCount();nCol++) 23 { 24 if(clrCol) 25 { 26 pDC->SetTextColor(clrCol[nCol]); 27 } 28 GetColumn(nCol,&lvColumn); 29 UINT uStyle=DT_SINGLELINE|DT_END_ELLIPSIS; 30 if(lvColumn.fmt&LVCFMT_LEFT) 31 uStyle|=DT_LEFT; 32 if(lvColumn.fmt&LVCFMT_RIGHT) 33 uStyle|=DT_RIGHT; 34 if(lvColumn.fmt&LVCFMT_CENTER) 35 uStyle|=DT_CENTER; 36 rcItem.right=rcItem.left+lvColumn.cx; 37 rcItem.left+=1; 38 if(((this->GetExtendedStyle() & LVS_EX_CHECKBOXES) == LVS_EX_CHECKBOXES) && nCol==0) 39 { 40 if(m_CheckItem.GetCount()>0) 41 { 42 Item_CheckBox *chkItem=m_CheckItem.GetAt(m_CheckItem.FindIndex(lpDIS->itemID)); 43 switch(chkItem->iState) 44 { 45 case 0: //未选 46 pDC->DrawFrameControl(CRect(rcItem.left+5,rcItem.top+2,rcItem.left+25,rcItem.bottom-2),DFC_BUTTON,DFCS_BUTTONCHECK); 47 break; 48 case 1://选中 49 pDC->DrawFrameControl(CRect(rcItem.left+5,rcItem.top+2,rcItem.left+25,rcItem.bottom-2),DFC_BUTTON,DFCS_CHECKED); 50 break; 51 case -1://置灰 52 pDC->DrawFrameControl(CRect(rcItem.left+5,rcItem.top+2,rcItem.left+25,rcItem.bottom-2),DFC_BUTTON,DFCS_INACTIVE); 53 break; 54 default: 55 break; 56 } 57 } 58 pDC->DrawText(GetItemText(lpDIS->itemID,nCol),CRect(rcItem.left+27,rcItem.top,rcItem.right,rcItem.bottom),uStyle); 59 } 60 else 61 { 62 pDC->DrawText(GetItemText(lpDIS-> itemID,nCol),rcItem,uStyle); 63 } 64 rcItem.left+=lvColumn.cx; 65 66 }
转载于:https://www.cnblogs.com/cuier/archive/2012/08/30/2663613.html