MFC类CBrush,CPen,CFont,CBitmap释放系统资源的问题

时间:2022-12-20 04:58:54
VC中的那些MFC类CBrush,CPen,CFont,在函数实现中(子程序中)定义了局部对象后,函数(子程序)执行完了后这些对象会析构,但好象这些MFC类的局部对象都需要手动添加代码使用  局部对象.DeleteObject()  去主动释放系统资源,为什么有些MFC类如CBitmap,CClientDC等类,会在它的局部对象结束时在它的析构函数中自动释放一些资源如位图资源,DC啊,我应该怎么知道哪些类在他的析构函数中会自动释放资源,哪些需要手动添加代码去主动释放资源,望指导!

23 个解决方案

#1


楼主说的这个问题的确是存在的 一开始编程序的时候 也经常会因为这些问题搞不清楚弄的内存泄露
程序运行缓慢等问题。

一下在把所有的东西都说清楚也不太可能 刚才去找了一下 有一个表 很全面 楼主可以参考一下
只是参考啊 其实程序编写好以后需要很多测试 在测试的过程中还需要更加精细 更加完善的检查

[VC/MFC]VC资源分配、释放表

#2


我还想问一下的是:MFC的类,如:
int CTextView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;

// TODO: Add your specialized creation code here
        //CBitmap bitmap;//如果bitmap对象定义在这里,那么OnCreate函数返回时bitmap对象析构了,
                             //并且好象是析构函数自动调用了bitmap.DeleteObject();从而导致字符
                             //插入符不显示.(故应把bitmap定义为CTextView的成员变量.)
                         //那CBrush,CPen,CFont的对象则必须手动添加 对象名.DeleteObject();
                         //来主动释放资源,这是不是意味这些类的默认析构函数没有自动调用了 对象
                             //名.DeleteObject();来自动释放资源?如果是的话,哪里有资料可查得到,以
                             //便验证这一想法,或者用什么办法可以让自己通过查看代码确认析构函数中
                             //是否已调用了         对象名.DeleteObject();            ???
CClientDC dc(this);
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
//CreateSolidCaret(tm.tmAveCharWidth/8,tm.tmHeight);
bitmap.LoadBitmap(IDB_BITMAP1);
CreateCaret(&bitmap);
ShowCaret();
return 0;
}


望指导!!!

#3


我觉得会出现你所说的那种情况主要跟 使用资源的对象和对象使用资源的方式有关系。

1.使用资源的对象可分为两类 局部和全局
2.使用资源的方式也分为两类 拷贝和指针

结合你的代码,CreateCaret创建提示符 虽然没有明确使用资源的是什么对象 但是去MSDN上就可以知道了 实际上使用提示符的是CTextView这个窗口
,是一个全局的对象。但是它使用资源的方式却可以认为是指针式的 即它在使用bitmap作为提示符时 其实并没有把bitmap拷贝一份 而是“寄希望于”它一直存在。这样 当你的bitmap是局部变量的时候 它就找不到这个资源了 也就没法显示提示符了。

但是当CDC* pDC; 使用CBrush,CPen,CFont时,pDC所指向的CDC是全局的 但是它使用资源的方式可以认为是拷贝式的 也就是当我们建立一个CPen pen; 并执行pDC->SelectObject(&pen);后,实际上相当于将pen拷贝了一份给CDC。这样 就算是pen是局部变量 在以后的使用过程中也会保持pen所代表的画笔。

既然如此 我想如果使用资源的对象是局部的话,也很容易解释了,就不多说了。
我对这个方面没有更深的理解了,上面也只是我自己按照自己的想法说的,楼主要找更加确切的东西,再问问高人 或者到MSDN上去找几个资源使用的例子 自己总结一下。
另外去参考一下: http://dev.21tx.com/2004/02/14/17312.html
上面这个文章当中提到了一个CGdiObject类的“虚拟析构函数”不知道是不是因为跟这个虚拟构造函数有关系(可能是基类没有实现这个析构函数)
另外 GDI的很多麻烦在GDI+中有很多已经没有了。GDI+中很多以前GDI中需要清理内存的地方都没有了。 GDI+是GDI的升级 学习方向应该向GDI+偏移。

#4


MFC类对象在析构时都会自动释放资源,不需要自己处理。只是当对象正在被使用的时候,例如对象被选入了某个DC中,此时对象是不能删除的,所以才会造成泄露。在使用SelectObject的时候,要保存其返回值,在用完之后再次调用SelectObject,选入上次的返回值。

#5


CreateXXX -> DeleteObject
GetXXX -> ReleaseObject
注意这些对应关系

#6


CClientDC 之类的东西,在其析构函数释放资源

而CBrush,CPen,CFont,却没有,需要显示释放,你可以自己做一个类,比如 CAutoFont,也在析构里面释放资源,不过感觉也没有感到好用

还是把我一个原则

Create  ,要有 Delete

Get, 要有 Release

#7


一直都没注意过这个问题啊。

#8


这些类都可以参看到源码,自己看一下就清楚了;GDI类关键是不要占用其资源,就都可以自己管理好GDI资源。

#9


mark
一下下

#10


还是有两点疑惑:
1.好象只可以看到CBrush的头文件AFXWIN.H,我在VC6.0中的实现文件AFXWIN.CPP没找不到CBrush的实现部分.不知道怎么才能
看CBrush类的实现源码
2.MSDN中确实也没有说这些类需要自己调用  局部对象.DeleteObject();  来释放资源(一般如果确实必须要调用局部对象.DeleteObject();  来自己释放资源的话MSDN都会很明确的指出),但不知道为什么好几个比较权威比较流行的视频教学或书籍及其例子中在ONPaint或ONDraw响应函数返回前都添加了  局部对象.DeleteObject();来释放资源.
 当然我知道,如果不使用MFC的类,而直接使用非面对对象的全局API的SDK编程,因为不存在对象,也就不存在析构函数,那是要遵循   
Create  ,要有 Delete 

Get, 要有 Release
的,
所以希望大牛们说说在ONPaint或ONDraw响应函数中定义了局部MFC GdiObject类对象(如CBrush,CPen,CFont,CBitmap),绘图完成并恢复了旧的(CBrush,CPen,CFont,CBitmap)对象后,我是否还必须要调用局部对象.DeleteObject();  来释放资源?
给分满24小时后再加100分,盼此一帖能解惑

#11


1,查看vc安装目录中的mfc代码
2. 一样的需要DeleteObject

#12


已经说了,不需要,但是一定要从DC中选出GDI对象

#13


1、首先安装VC时要安装源代码,调试程序时可以用F11跟踪到MFC的源代码里面。
2、CBrush,CPen,CFont,CBitmap都是从CGdiObject类派生的,CGdiObject的析构函数中会调用DeleteObject,所以在对象销毁前自己用代码DeleteObject是多余的。不知道你所说的“权威”是谁,这方面只有MS是权威。

#14


学习了!谢谢

#15


再次查看了手头的资料发现它们只是在创建了CFont对象并使用完后才会手动添加局部对象.DeleteObject();来
释放资源,经查MSDN发现:1.CFont
   When you finish with the CFont object created by the CreateFontIndirect function, first select the font out of the device context, then delete the CFont object.

When you finish with the CFont object created by the CreateFont function, first select the font out of the device context, then delete the CFont object.

When you finish with the CFont object created by the CreatePointFont function, first select the font out of the device context, then delete the CFont object.

When you finish with the CFont object created by the CreatePointFontIndirect function, first select the font out of the device context, then delete the CFont object.

2.CBitmap
You can use the CGdiObject::DeleteObject function to delete bitmap loaded by the LoadBitmap function, or the CBitmap destructor will delete the object for you. 

When you finish with the CBitmap object created by the CreateBitmap function, first select the bitmap out of the device context, then delete the CBitmap object.

When you finish with the CBitmap object created with CreateBitmapIndirect function, first select the bitmap out of the device context, then delete the CBitmap object.
3.CBrush
CBrush::CBrush()If you use the constructor with no arguments, you must initialize the resulting CBrush object with CreateSolidBrush, CreateHatchBrush, CreateBrushIndirect, CreatePatternBrush, or CreateDIBPatternBrush. If you use one of the constructors that takes arguments, then no further initialization is necessary. The constructors with arguments can throw an exception if errors are encountered, while the constructor with no arguments will always succeed.

When an application has finished using the brush created by CreateSolidBrush, it should select the brush out of the device context.

BOOL CreateHatchBrush( int nIndex, COLORREF crColor );Initializes a brush with the specified hatched pattern and color. The brush can subsequently be selected as the current brush for any device context.
4.CPen
CPen::CPen() If you use the constructor with no arguments, you must initialize the resulting CPen object with the CreatePen, CreatePenIndirect, or CreateStockObject member functions. If you use the constructor that takes arguments, then no further initialization is necessary. The constructor with arguments can throw an exception if errors are encountered, while the constructor with no arguments will always succeed.
CPen::CreatePen() When an application no longer requires a given pen, it should call the CGdiObject::DeleteObject member function or destroy the CPen object so the resource is no longer in use. An application should not delete a pen when the pen is selected in a device context.
感谢大牛们指导!!!加分后结帖







#16


CFont也是从CGdiObject类派生的,析构时会自动DeleteObject。
这段英文的意思是:在销毁对象之前,要先把对象从DC中选出(否则DeleteObject会失败)。

#17


我觉得会出现你所说的那种情况主要跟 使用资源的对象和对象使用资源的方式有关系。 

1.使用资源的对象可分为两类 局部和全局 
2.使用资源的方式也分为两类 拷贝和指针 

结合你的代码,CreateCaret创建提示符 虽然没有明确使用资源的是什么对象 但是去MSDN上就可以知道了 实际上使用提示符的是CTextView这个窗口 
,是一个全局的对象。但是它使用资源的方式却可以认为是指针式的 即它在使用bitmap作为提示符时 其实并没有把bitmap拷贝一份 而是“寄希望于”它一直存在。这样 当你的bitmap是局部变量的时候 它就找不到这个资源了 也就没法显示提示符了。 

但是当CDC* pDC; 使用CBrush,CPen,CFont时,pDC所指向的CDC是全局的 但是它使用资源的方式可以认为是拷贝式的 也就是当我们建立一个CPen pen; 并执行pDC->SelectObject(&pen);后,实际上相当于将pen拷贝了一份给CDC。这样 就算是pen是局部变量 在以后的使用过程中也会保持pen所代表的画笔。 

既然如此 我想如果使用资源的对象是局部的话,也很容易解释了,就不多说了。 
我对这个方面没有更深的理解了,上面也只是我自己按照自己的想法说的,楼主要找更加确切的东西,再问问高人 或者到MSDN上去找几个资源使用的例子 自己总结一下。 
另外去参考一下:http://dev.21tx.com/2004/02/14/17312.html 
上面这个文章当中提到了一个CGdiObject类的“虚拟析构函数”不知道是不是因为跟这个虚拟构造函数有关系(可能是基类没有实现这个析构函数) 
另外 GDI的很多麻烦在GDI+中有很多已经没有了。GDI+中很多以前GDI中需要清理内存的地方都没有了。 GDI+是GDI的升级 学习方向应该向GDI+偏移。

#18


学习

#19


碰到跟楼主一样的问题,一样的困惑!
百度的时候刚好搜到这里!
感觉上2楼的朋友解释是比较到位的,但是还是有一点疑惑:
什么样的对象使用资源对象时候,资源对象需要定义为一个全局的?
根据2楼朋友的解释:取决于使用方使用资源的方式 为两类 拷贝和指针!
但是我们怎么知道使用方使用资源的方式?
msdn吗?
查了一下,似乎没有!

#20


cnzdgs (16楼) 一语点破要害!说得很到位,我终于知道问题所在了。

#21


我再想插最后一句话。
楼上这些大虾说的都对,但是作为良好的编程习惯,还是应该把Create和Delete对应起来。
的确,MFC析构时,会自动释放资源(调用DeleteObject),但是你主动释放又有何坏处呢?

另外,还会有一种情况,大虾可能不会犯错,菜鸟就未必了。
void func()
{
    CClientDC dc(this);
    CFont font;
    font.CreateFont(......);
    CFont* pOldFont = dc.SelectObject(&font);
    //绘制一些文字
    font.CreateFont(......);
    pOldFont = dc.SelectObject(&font);
    //再绘制一些文字

    dc.SelectObject(pOldFont);
}

这里就会出现资源泄漏,除非你自己 DeleteObject。
总之,什么时候该清除创建出的GDI资源,心里要清除,不管是主动清除还是靠析构。

#22


void func()
{
  CClientDC dc(this);
  CFont font;
  font.CreateFont(......);
  CFont* pOldFont = dc.SelectObject(&font);
  //绘制一些文字
  font.CreateFont(......);
  pOldFont = dc.SelectObject(&font);
  //再绘制一些文字

  dc.SelectObject(pOldFont);
}
//第一个创建的字体为A,第一个oldfont为B,
1.在创建第二个字体C的时候,B就被释放掉了,但B未被选出,所以释放失败,需要在第二个font.CreateFont(......);前添加 dc.SelectObject(pOldFont);
2.最后面的 dc.SelectObject(pOldFont);  这里的pOldFont,如果没有进行1的步骤,则是之前未释放掉的B。


总之切记两点,第一最好不要把一个对象来重复使用,容易出错
第二不要在 dc.SelectObject(pOldFont);之前销毁对象,我的系统只要这样做一次,WPFFONT.exe每次一运行就直飚25%。

#23


mark  mark up

#1


楼主说的这个问题的确是存在的 一开始编程序的时候 也经常会因为这些问题搞不清楚弄的内存泄露
程序运行缓慢等问题。

一下在把所有的东西都说清楚也不太可能 刚才去找了一下 有一个表 很全面 楼主可以参考一下
只是参考啊 其实程序编写好以后需要很多测试 在测试的过程中还需要更加精细 更加完善的检查

[VC/MFC]VC资源分配、释放表

#2


我还想问一下的是:MFC的类,如:
int CTextView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;

// TODO: Add your specialized creation code here
        //CBitmap bitmap;//如果bitmap对象定义在这里,那么OnCreate函数返回时bitmap对象析构了,
                             //并且好象是析构函数自动调用了bitmap.DeleteObject();从而导致字符
                             //插入符不显示.(故应把bitmap定义为CTextView的成员变量.)
                         //那CBrush,CPen,CFont的对象则必须手动添加 对象名.DeleteObject();
                         //来主动释放资源,这是不是意味这些类的默认析构函数没有自动调用了 对象
                             //名.DeleteObject();来自动释放资源?如果是的话,哪里有资料可查得到,以
                             //便验证这一想法,或者用什么办法可以让自己通过查看代码确认析构函数中
                             //是否已调用了         对象名.DeleteObject();            ???
CClientDC dc(this);
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
//CreateSolidCaret(tm.tmAveCharWidth/8,tm.tmHeight);
bitmap.LoadBitmap(IDB_BITMAP1);
CreateCaret(&bitmap);
ShowCaret();
return 0;
}


望指导!!!

#3


我觉得会出现你所说的那种情况主要跟 使用资源的对象和对象使用资源的方式有关系。

1.使用资源的对象可分为两类 局部和全局
2.使用资源的方式也分为两类 拷贝和指针

结合你的代码,CreateCaret创建提示符 虽然没有明确使用资源的是什么对象 但是去MSDN上就可以知道了 实际上使用提示符的是CTextView这个窗口
,是一个全局的对象。但是它使用资源的方式却可以认为是指针式的 即它在使用bitmap作为提示符时 其实并没有把bitmap拷贝一份 而是“寄希望于”它一直存在。这样 当你的bitmap是局部变量的时候 它就找不到这个资源了 也就没法显示提示符了。

但是当CDC* pDC; 使用CBrush,CPen,CFont时,pDC所指向的CDC是全局的 但是它使用资源的方式可以认为是拷贝式的 也就是当我们建立一个CPen pen; 并执行pDC->SelectObject(&pen);后,实际上相当于将pen拷贝了一份给CDC。这样 就算是pen是局部变量 在以后的使用过程中也会保持pen所代表的画笔。

既然如此 我想如果使用资源的对象是局部的话,也很容易解释了,就不多说了。
我对这个方面没有更深的理解了,上面也只是我自己按照自己的想法说的,楼主要找更加确切的东西,再问问高人 或者到MSDN上去找几个资源使用的例子 自己总结一下。
另外去参考一下: http://dev.21tx.com/2004/02/14/17312.html
上面这个文章当中提到了一个CGdiObject类的“虚拟析构函数”不知道是不是因为跟这个虚拟构造函数有关系(可能是基类没有实现这个析构函数)
另外 GDI的很多麻烦在GDI+中有很多已经没有了。GDI+中很多以前GDI中需要清理内存的地方都没有了。 GDI+是GDI的升级 学习方向应该向GDI+偏移。

#4


MFC类对象在析构时都会自动释放资源,不需要自己处理。只是当对象正在被使用的时候,例如对象被选入了某个DC中,此时对象是不能删除的,所以才会造成泄露。在使用SelectObject的时候,要保存其返回值,在用完之后再次调用SelectObject,选入上次的返回值。

#5


CreateXXX -> DeleteObject
GetXXX -> ReleaseObject
注意这些对应关系

#6


CClientDC 之类的东西,在其析构函数释放资源

而CBrush,CPen,CFont,却没有,需要显示释放,你可以自己做一个类,比如 CAutoFont,也在析构里面释放资源,不过感觉也没有感到好用

还是把我一个原则

Create  ,要有 Delete

Get, 要有 Release

#7


一直都没注意过这个问题啊。

#8


这些类都可以参看到源码,自己看一下就清楚了;GDI类关键是不要占用其资源,就都可以自己管理好GDI资源。

#9


mark
一下下

#10


还是有两点疑惑:
1.好象只可以看到CBrush的头文件AFXWIN.H,我在VC6.0中的实现文件AFXWIN.CPP没找不到CBrush的实现部分.不知道怎么才能
看CBrush类的实现源码
2.MSDN中确实也没有说这些类需要自己调用  局部对象.DeleteObject();  来释放资源(一般如果确实必须要调用局部对象.DeleteObject();  来自己释放资源的话MSDN都会很明确的指出),但不知道为什么好几个比较权威比较流行的视频教学或书籍及其例子中在ONPaint或ONDraw响应函数返回前都添加了  局部对象.DeleteObject();来释放资源.
 当然我知道,如果不使用MFC的类,而直接使用非面对对象的全局API的SDK编程,因为不存在对象,也就不存在析构函数,那是要遵循   
Create  ,要有 Delete 

Get, 要有 Release
的,
所以希望大牛们说说在ONPaint或ONDraw响应函数中定义了局部MFC GdiObject类对象(如CBrush,CPen,CFont,CBitmap),绘图完成并恢复了旧的(CBrush,CPen,CFont,CBitmap)对象后,我是否还必须要调用局部对象.DeleteObject();  来释放资源?
给分满24小时后再加100分,盼此一帖能解惑

#11


1,查看vc安装目录中的mfc代码
2. 一样的需要DeleteObject

#12


已经说了,不需要,但是一定要从DC中选出GDI对象

#13


1、首先安装VC时要安装源代码,调试程序时可以用F11跟踪到MFC的源代码里面。
2、CBrush,CPen,CFont,CBitmap都是从CGdiObject类派生的,CGdiObject的析构函数中会调用DeleteObject,所以在对象销毁前自己用代码DeleteObject是多余的。不知道你所说的“权威”是谁,这方面只有MS是权威。

#14


学习了!谢谢

#15


再次查看了手头的资料发现它们只是在创建了CFont对象并使用完后才会手动添加局部对象.DeleteObject();来
释放资源,经查MSDN发现:1.CFont
   When you finish with the CFont object created by the CreateFontIndirect function, first select the font out of the device context, then delete the CFont object.

When you finish with the CFont object created by the CreateFont function, first select the font out of the device context, then delete the CFont object.

When you finish with the CFont object created by the CreatePointFont function, first select the font out of the device context, then delete the CFont object.

When you finish with the CFont object created by the CreatePointFontIndirect function, first select the font out of the device context, then delete the CFont object.

2.CBitmap
You can use the CGdiObject::DeleteObject function to delete bitmap loaded by the LoadBitmap function, or the CBitmap destructor will delete the object for you. 

When you finish with the CBitmap object created by the CreateBitmap function, first select the bitmap out of the device context, then delete the CBitmap object.

When you finish with the CBitmap object created with CreateBitmapIndirect function, first select the bitmap out of the device context, then delete the CBitmap object.
3.CBrush
CBrush::CBrush()If you use the constructor with no arguments, you must initialize the resulting CBrush object with CreateSolidBrush, CreateHatchBrush, CreateBrushIndirect, CreatePatternBrush, or CreateDIBPatternBrush. If you use one of the constructors that takes arguments, then no further initialization is necessary. The constructors with arguments can throw an exception if errors are encountered, while the constructor with no arguments will always succeed.

When an application has finished using the brush created by CreateSolidBrush, it should select the brush out of the device context.

BOOL CreateHatchBrush( int nIndex, COLORREF crColor );Initializes a brush with the specified hatched pattern and color. The brush can subsequently be selected as the current brush for any device context.
4.CPen
CPen::CPen() If you use the constructor with no arguments, you must initialize the resulting CPen object with the CreatePen, CreatePenIndirect, or CreateStockObject member functions. If you use the constructor that takes arguments, then no further initialization is necessary. The constructor with arguments can throw an exception if errors are encountered, while the constructor with no arguments will always succeed.
CPen::CreatePen() When an application no longer requires a given pen, it should call the CGdiObject::DeleteObject member function or destroy the CPen object so the resource is no longer in use. An application should not delete a pen when the pen is selected in a device context.
感谢大牛们指导!!!加分后结帖







#16


CFont也是从CGdiObject类派生的,析构时会自动DeleteObject。
这段英文的意思是:在销毁对象之前,要先把对象从DC中选出(否则DeleteObject会失败)。

#17


我觉得会出现你所说的那种情况主要跟 使用资源的对象和对象使用资源的方式有关系。 

1.使用资源的对象可分为两类 局部和全局 
2.使用资源的方式也分为两类 拷贝和指针 

结合你的代码,CreateCaret创建提示符 虽然没有明确使用资源的是什么对象 但是去MSDN上就可以知道了 实际上使用提示符的是CTextView这个窗口 
,是一个全局的对象。但是它使用资源的方式却可以认为是指针式的 即它在使用bitmap作为提示符时 其实并没有把bitmap拷贝一份 而是“寄希望于”它一直存在。这样 当你的bitmap是局部变量的时候 它就找不到这个资源了 也就没法显示提示符了。 

但是当CDC* pDC; 使用CBrush,CPen,CFont时,pDC所指向的CDC是全局的 但是它使用资源的方式可以认为是拷贝式的 也就是当我们建立一个CPen pen; 并执行pDC->SelectObject(&pen);后,实际上相当于将pen拷贝了一份给CDC。这样 就算是pen是局部变量 在以后的使用过程中也会保持pen所代表的画笔。 

既然如此 我想如果使用资源的对象是局部的话,也很容易解释了,就不多说了。 
我对这个方面没有更深的理解了,上面也只是我自己按照自己的想法说的,楼主要找更加确切的东西,再问问高人 或者到MSDN上去找几个资源使用的例子 自己总结一下。 
另外去参考一下:http://dev.21tx.com/2004/02/14/17312.html 
上面这个文章当中提到了一个CGdiObject类的“虚拟析构函数”不知道是不是因为跟这个虚拟构造函数有关系(可能是基类没有实现这个析构函数) 
另外 GDI的很多麻烦在GDI+中有很多已经没有了。GDI+中很多以前GDI中需要清理内存的地方都没有了。 GDI+是GDI的升级 学习方向应该向GDI+偏移。

#18


学习

#19


碰到跟楼主一样的问题,一样的困惑!
百度的时候刚好搜到这里!
感觉上2楼的朋友解释是比较到位的,但是还是有一点疑惑:
什么样的对象使用资源对象时候,资源对象需要定义为一个全局的?
根据2楼朋友的解释:取决于使用方使用资源的方式 为两类 拷贝和指针!
但是我们怎么知道使用方使用资源的方式?
msdn吗?
查了一下,似乎没有!

#20


cnzdgs (16楼) 一语点破要害!说得很到位,我终于知道问题所在了。

#21


我再想插最后一句话。
楼上这些大虾说的都对,但是作为良好的编程习惯,还是应该把Create和Delete对应起来。
的确,MFC析构时,会自动释放资源(调用DeleteObject),但是你主动释放又有何坏处呢?

另外,还会有一种情况,大虾可能不会犯错,菜鸟就未必了。
void func()
{
    CClientDC dc(this);
    CFont font;
    font.CreateFont(......);
    CFont* pOldFont = dc.SelectObject(&font);
    //绘制一些文字
    font.CreateFont(......);
    pOldFont = dc.SelectObject(&font);
    //再绘制一些文字

    dc.SelectObject(pOldFont);
}

这里就会出现资源泄漏,除非你自己 DeleteObject。
总之,什么时候该清除创建出的GDI资源,心里要清除,不管是主动清除还是靠析构。

#22


void func()
{
  CClientDC dc(this);
  CFont font;
  font.CreateFont(......);
  CFont* pOldFont = dc.SelectObject(&font);
  //绘制一些文字
  font.CreateFont(......);
  pOldFont = dc.SelectObject(&font);
  //再绘制一些文字

  dc.SelectObject(pOldFont);
}
//第一个创建的字体为A,第一个oldfont为B,
1.在创建第二个字体C的时候,B就被释放掉了,但B未被选出,所以释放失败,需要在第二个font.CreateFont(......);前添加 dc.SelectObject(pOldFont);
2.最后面的 dc.SelectObject(pOldFont);  这里的pOldFont,如果没有进行1的步骤,则是之前未释放掉的B。


总之切记两点,第一最好不要把一个对象来重复使用,容易出错
第二不要在 dc.SelectObject(pOldFont);之前销毁对象,我的系统只要这样做一次,WPFFONT.exe每次一运行就直飚25%。

#23


mark  mark up