下面这个图引用书上的一段话:书上的意思应该是说CBrush对象应该在CPaintDC对象之前调用析构函数,因为在栈上CBrush后于CPaintDC创建,这是这句话没明白:"相关的GDI画刷在dc超出范围之前就被删除了"。没搞明白什么叫dc超出范围之前,dc在什么情况下会超出范围了?删除gdi画刷究竟又是什么时候发生的了?小弟初学,不明白以上问题,还望这里的朋友指点了。
调试欢乐多
堆栈是一种后进先出的数据结构.
CBrush既然比CPainDC晚创建,就肯定比CPainDC早出栈.
也就是CBrush会在CPainDC析构前先析构!
CDC对象一旦解析之后,并不会把其中的对象全部解析。
书上的意思是说:
函数的返回时,在函数内部的对象的析构顺序与它们的创建顺序相反,CPaintDC是于CBrush与创建的,
所以CPaintDC在CBrush之后析构。这个顺序比较完美一点。
但是,至于为什么说,这样的程序太可怕了,我完全想不明白。
这个估计是翻译错误:应该是:
相关的GDI画刷在dc析构之前就被析构了
照这个说法,对于一个窗口类的成员对象m_Brush,一旦被某个局部对象CDC使用过,就会被删除其上的GDI内容,
就不能再被其它CDC选入使用了。但是事实证明,m_Brush可以被多个CDC对象重复使用。
就算是DCD析构时使用了DeleteObject,DeleteObject失败之后,哪些资源被泄露了?
删除失败只是证明,该资源已经被删除过了,因而不能被重复删除。所以,资源已经被释放了。没有资源泄漏存在。
SelectObject在使用时要选出旧刷子,使用完毕后再把就刷子选入的原因是:
对于全局/成员DC或者系统DC,你用完后,总得把人家的东西还给人家吧?要不然下次人家再使用时,发现:咦?我的东西怎么不见了。
但是对于一个局部对象的DC来说,根本不必要再次选入旧GDI对象。另外全局/成员DC如果没有使用全局/成员GDI对象的话,使用SelectObject也不必再次选入旧GDI对象。有什么地方不对请指正。
这个还要在说明一下:
假如DC是系统的,那么,对于DC上原有旧对象,系统可能会在某些情况下要进行删除其上对象的操作,以用来释放资源。
这个时候如果原有的对象没有被选入,那么就会存在资源泄漏。
不过这是对于系统DC或者别人写的DC而言的。当然,如果你自己写的全局/成员DC,由于代码太长,你也可能不知道自己做了哪些操作,所以SelectObject也要选入旧对象。
但是,一个函数内部的局部对象DC,没必要再选入旧对象。除非这函数超过几百行。
DC与GDI对象是分离的
只有在SelectObject后才有关系
书上说的也没错
在 建立关系后 DC销毁时对GDI对象没有影响
只有在函数退出时 才销毁 GDI对象
在函数使用DC时 DC是已经初始化过的
不会存在泄漏问题
函数内部的 DC就不用 选择回去了
你的依据是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.