我试图弄清楚如何在C ++ / CLI中正确清理我的对象。
我已阅读或浏览过这两篇文章(one,two),并查看了the standard并查看了其他一些问题this one。
我有各种各样的信息:
但是,由于
这一事实导致了很多混乱我想要的答案是一个类的例子,它包含它可能包含的所有不同类型的数据(托管,非托管,托管但是一次性的,你能想到的其他任何东西)以及正确编写的析构函数和终结器。
我还有两个更具体的问题:
bool hasBeenCleanedUp
成员处理多次被调用的可能性并使析构函数/终结符中的整个代码以此为条件可以接受吗?答案 0 :(得分:5)
对您的问题不是一个完整的答案,但是太长,无法发表评论。
在完全托管的世界中,每个对象只引用托管对象,不需要终结器或析构函数,因为唯一的资源是内存和 GC会照顾它。
当您引用非托管资源时,如果您不再需要它,则有责任释放它们。
因此,您需要实施专用清理代码。
有两种可能性:
你知道当你不再需要非托管资源时,你可以确定性地运行你的清理代码,这是通过析构函数/ Dispose 实现的
你不知道什么时候不再需要这些资源所以你在最后一刻推迟清理,当GC收集包装资源的对象时,这是通过终结者
您认为在第一种情况下更好,因为您不会消耗超过您需要的内存,并且可以避免GC流程的额外开销。
您通常同时实现这两者,因为实例的生命周期可能因使用情况而异。
在 CLR级别,没有确定性清理,只有终结器。
在语言/ API级别,支持确定性清理:
在本机C ++中,您在退出作用域或“删除”时会调用析构函数
在.Net世界中,你有Dispose模式
在纯托管C ++ / CLI中,世界析构函数映射到Dispose
当您有机会确切知道何时可以运行清理代码时,您可以调用(或让基础架构调用)析构函数。清理完成后,您可以摆脱所有的完成过程,以便在下一个GC时立即收集对象。
关于你的第一个要点的一些澄清:
是
析构函数也负责清理非托管资源;它可以调用终结器,如果它是你清理代码的因素。
他们在技术上可以但逻辑上你应该用一个简单的布尔警卫来阻止它
是的,因为所有的清理都应该完成,所以你要求CLR不要最终确定对象
是的,因为基类知道它分配了哪些资源
是的,这是用于确定性清理
你应该确保是这种情况
其他人:
是~MyClass映射到Finalize方法的覆盖
如上所述,析构函数映射到Dispose,但您应该自己实现终结器:!MyClass
总结:C ++析构函数和Dispose模式用于确定性清理,C#析构函数,C ++ / CLI终结器用于由GC触发的非确定性清理。