当对象释放时,避免析构函数调用两次

当对象释放时,避免析构函数调用两次

作者:BlogUpdater |  时间:2023-04-16 |  浏览:713 |  评论已关闭 条评论

在上一篇文章中,我们提到过,在一个对象的析构函数中执行太多任务,可能导致对象被释放两次。解决此问题的标准方法是在析构过程中使用一个自定义的引用计数,如下图所示:

如果你有 IUnknown 接口的通用实现,则可以像我们在此处所做的那样,在 IUnknown 接口的 Release 方法中将引用计数设置为 DESTRUCTOR_REFCOUNT,并在实现的析构函数中断言该值是正确的。

由于 C++ 在派生类析构函数之后运行基类析构函数,因此基类析构函数将在派生类完成清理后检查引用计数。

通过将引用计数设置为人为的非零值,发生的任何 AddRef 和 Release 调用都不会触发重复销毁(当然,假设析构函数路径中没有人有导致它们过度释放的错误)。末尾的断言可确保在销毁过程中不会创建对对象的新引用。

这实际上更像是一种解决方法,而不是坚如磐石的解决方案,因为它假定在销毁序列期间调用的任何函数都不会保留对函数返回之外的对象的引用。这通常不是你可以假设的关于 COM 的事情。通常,方法可以自由调用 AddRef 并挂在指向对象的指针上,以便稍后完成请求的操作。

某些方法(如 IPersistPropertyBag 接口的 Load 方法) 明确禁止此类行为,但这些类型的方法更像是例外而不是规则。

课后练习题
为什么执行简单的赋值操作 m_cRef = DESTRUCTOR_REFCOUNT,而不是更复杂的互锁交换 InterlockedExchangeAdd(&m_cRef,DESTRUCTOR_REFCOUNT),这样岂不是更安全的?

总结
图中的技法,可以加以利用,以确认对象的析构函数确实仅会被释放一次。
你的技能工具箱里又多了一把趁手的小玩意儿了。

最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《Avoiding double-destruction when an object is released》

最近我写了个东西
正如你们所知道的,拓扑梅尔智慧办公平台(Topomel Box)是一款绿色软件,主要面向经常使用电脑的朋友。它提供了各种提升办公效率的小功能,同时操作上尽可能地简单方便。
我想:你值得拥有。

标签:

评论已关闭。