第一部分:关于析构函数何时执行

第一部分:关于析构函数何时执行

作者:BlogUpdater |  时间:2021-03-09 |  浏览:1111 |  评论已关闭 条评论

C++: 一座看不见的冰山
Larry Osterman在他的博客中讨论全局对象析构函数执行时的细节,我想说的是,其实不仅是全局对象,对于局部对象来说,它的析构函数的执行时间点也十分重要,你需要谨慎地处理,方能确保安全。我们先考虑下面的代码:

代码看起来再简单不过了,但是请注意,上述代码蕴含Bug一枚。

问题:智能指针的析构函数何时运行?
答案:如果对象超出作用域,也就是在执行到最外层的if语句之外时,并且在CoUninitialize调用之后才会执行其析构函数。

所以,如果这个时候你已经释放了COM库,并且还尝试着去访问一个COM对象,这可不是什么好事儿。

为了修复这个问题,你需要在CoUninitialize调用之前完成所有COM指针的释放。一种可以想到的方法是:在内层if语句结束的地方添加一个p.Release()调用,但是,当然了,如果你打算这样做的话,那为什么一开始要使用一个智能指针呢?

另外一个方法是:引入一个看起来没有什么意义的作用域,如下图所示:

请确保你编写清晰明确的注释,要不然代码的维护者可能会因为这里的重复的括号而将它们优化掉,就会导致问题。

当然,这种做法还不是最完美的。下面我们展示另外一种解决方案:将CoUninitialize放到一个它自己的析构函数中。如下图所示:

在上述做法中,即使你将智能指针放到同一个作用域也没有问题,只要你将它放在CCoInitialize对象之后,你就是安全的。

这种做法能正常工作的原因在于:对象的析构顺序和它声明的顺序相反,也即:对象p会先被释放,然后是对象init的释放。

总结
编程之路上,没有人能随随便便成功,请期待第二部分。

最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《Do you know when your destructors run? Part 1.》

评论已关闭。