COM 对象析构函数是非常敏感的函数
如果你试图在 COM 对象的析构函数中做太多事情,你会发现自己有麻烦。
此话怎讲?
举个例子,如果析构函数将自身引用交给其他函数,则这些函数可能会决定调用 IUnknown::AddRef 和 IUnknown::Release 方法作为其内部操作的一部分。考察下面的代码:
现在看起来不那么可怕了吧?对象在销毁时会调用 Save 保存自身。
但是,Save 方法可能会执行以下操作:
就其本身而言,上面的代码看起来很正常。获取 IStream 并保存到它,将自己设置为其站点,以防 IStream 想要获取有关对象的其他信息作为保存过程的一部分。
但是,结合我们从析构函数中调用它的事实,这可能是一个灾难。观察释放最后一个引用时会发生什么情况。
> Release 方法将引用计数递减为零并执行删除此操作。
> 析构函数尝试保存对象。
> Save 方法获取存储流并将自身设置为站点。这会将引用计数从 0 增加到 1。
> SaveToStream 方法保存对象。
> Save 方法清除流上的站点。这会将引用计数从 1 减回零。
> 因此,Release 方法尝试第二次析构对象。
重复调用析构函数,可能往往会导致混乱。如果你幸运的话,你会在递归破坏中崩溃并识别来源,但如果你不幸运,由此产生的堆损坏在相当长的一段时间内不会被检测到,此时你只会挠头。
因此,至少应在 AddRef 方法中断言引用计数不会从零递增,如下图所示:
这可以帮助我们尽早地发现重复调用析构函数的情况,让你有机会发现问题。但是,一旦你发现了问题,你能做些什么呢?
我们下次会研究这个问题。
总结
COM 对象基于引用计数的方式来管理对象的生存周期,这也导致了各种潜在的内存泄露问题,因为每一次的 AddRef,都必须有一个,且仅有一个 Release 与之伴随。
如果两者调用次数不匹配,则可能会出乱子。更糟糕的是,可能是程序运行了很久,在远离案发现场的地方出乱子。
这个时候如果想调试问题,就不大容易了。所以:请善用智能指针。
最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《COM object destructors are very sensitive functions》
最近我写了个东西
正如你们所知道的,拓扑梅尔智慧办公平台(Topomel Box)是一款绿色软件,主要面向经常使用电脑的朋友。它提供了各种提升办公效率的小功能,同时操作上尽可能地简单方便。
我想:你值得拥有。
相关推荐
- 说说经理和程序员的区别
- Posted on 05月07日
- 实战经验:为本地服务器创建自签名证书链
- Posted on 07月29日
- 对话框模板简史-16位扩展模板
- Posted on 04月16日
- 深度理解:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- Posted on 08月13日
评论已关闭。