第一次用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)文字常量区 — 常量字符串就是放在这里的,程序结束后由系统释放 。
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 }