下面这个图引用书上的一段话:书上的意思应该是说CBrush对象应该在CPaintDC对象之前调用析构函数,因为在栈上CBrush后于CPaintDC创建,这是这句话没明白:"相关的GDI画刷在dc超出范围之前就被删除了"。没搞明白什么叫dc超出范围之前,dc在什么情况下会超出范围了?删除gdi画刷究竟又是什么时候发生的了?小弟初学,不明白以上问题,还望这里的朋友指点了。

解决方案 »

  1.   

    虽然我不知道,但是我猜测,对于选入CDC中的对象,CDC对象一旦解析之后,会把其中的对象全部解析,包括CPen等。所以,如果一个画刷如果创建在CDC之外,就要小心使用。
      

  2.   

    你应该明白堆栈的意思吧!
    堆栈是一种后进先出的数据结构.
    CBrush既然比CPainDC晚创建,就肯定比CPainDC早出栈.
    也就是CBrush会在CPainDC析构前先析构!
      

  3.   

    我上面的说法错误了。不好意思。
    CDC对象一旦解析之后,并不会把其中的对象全部解析。
    书上的意思是说:
    函数的返回时,在函数内部的对象的析构顺序与它们的创建顺序相反,CPaintDC是于CBrush与创建的,
    所以CPaintDC在CBrush之后析构。这个顺序比较完美一点。
    但是,至于为什么说,这样的程序太可怕了,我完全想不明白。
      

  4.   

    相关的GDI画刷在dc超出范围之前就被删除了
    这个估计是翻译错误:应该是:
    相关的GDI画刷在dc析构之前就被析构了
      

  5.   

    这本书写得有问题。正确的做法是在dc超出范围之前就选择原来的画刷,将创建的画刷替换出DC。否则因为画刷在被DC使用中,即使CBrush的析构函数被调用,析构函数调用的DeleteObject也会失败,造成资源泄漏。
      

  6.   

    谢谢楼上某位朋友,栈的意思我是明白的,我一路看下来,楼上jiangsheng兄的说我觉是应该是对的。不过还是有点疑问,dc超过范围说的到底是什么情况?意思是dc被释放的时候?这些东西怎么写得都不明不白的?
      

  7.   

    请问jiangsheng,为什么说会造成资源泄漏?你确定CDC在析构时会使用DeleteObject去删除对象?
    照这个说法,对于一个窗口类的成员对象m_Brush,一旦被某个局部对象CDC使用过,就会被删除其上的GDI内容,
    就不能再被其它CDC选入使用了。但是事实证明,m_Brush可以被多个CDC对象重复使用。
    就算是DCD析构时使用了DeleteObject,DeleteObject失败之后,哪些资源被泄露了?
    删除失败只是证明,该资源已经被删除过了,因而不能被重复删除。所以,资源已经被释放了。没有资源泄漏存在。
    SelectObject在使用时要选出旧刷子,使用完毕后再把就刷子选入的原因是:
    对于全局/成员DC或者系统DC,你用完后,总得把人家的东西还给人家吧?要不然下次人家再使用时,发现:咦?我的东西怎么不见了。
    但是对于一个局部对象的DC来说,根本不必要再次选入旧GDI对象。另外全局/成员DC如果没有使用全局/成员GDI对象的话,使用SelectObject也不必再次选入旧GDI对象。有什么地方不对请指正。
      

  8.   

    补充一下:
    这个还要在说明一下:
    假如DC是系统的,那么,对于DC上原有旧对象,系统可能会在某些情况下要进行删除其上对象的操作,以用来释放资源。
    这个时候如果原有的对象没有被选入,那么就会存在资源泄漏。
    不过这是对于系统DC或者别人写的DC而言的。当然,如果你自己写的全局/成员DC,由于代码太长,你也可能不知道自己做了哪些操作,所以SelectObject也要选入旧对象。
    但是,一个函数内部的局部对象DC,没必要再选入旧对象。除非这函数超过几百行。
      

  9.   

    明白了不少东西,等待jiangsheng兄,和其它朋友的回复,对于书上这段是写错了还是怎么样,希望大家都来发表下自已的意见。
      

  10.   

    9楼说的对
    DC与GDI对象是分离的 
    只有在SelectObject后才有关系 
    书上说的也没错
    在 建立关系后 DC销毁时对GDI对象没有影响 
    只有在函数退出时  才销毁 GDI对象 
    在函数使用DC时  DC是已经初始化过的  
    不会存在泄漏问题
    函数内部的 DC就不用 选择回去了
      

  11.   

    我现在明白你的意思,你是说CBrush析构时,它将调用的DeleteObject删除画刷句柄。但是因为画刷在被DC使用中,所以DeleteObject失败.
    你的依据是MSDN:DeleteObject
    “If the specified handle is not valid or is currently selected into a DC, the return value is zero”
    你自己可以去证明,MSDN的上的说法是错误的。
    无论是任何GDI对象,只要是有效的,即使正在被DC使用,依然可以被DeleteObject删除成功,并且不返回0.