管理托管(C#)和非托管(C++)对象的析构函数

4 c# c++ destructor unmanaged managed

我在ac#dll中有一个托管对象,它维护一个c ++ dll中非托管对象的匿名整数句柄.在c ++ dll中,匿名整数在std :: map中用于检索非托管c ++对象.通过这种机制,我可以使用匿名整数句柄维护托管和非托管对象之间的松散关联.

在托管对象的finalize方法(析构函数)中,我调用了非托管dll来删除非托管对象.

一切顺利,因为c#程序运行,但程序退出时我遇到了问题.因为我无法控制托管端的删除操作顺序,所以在任何托管对象之前从内存中删除非托管dll.因此,当调用托管对象的析构函数(后者又调用非托管析构函数[至少间接调用])时,非托管对象已被删除,程序崩溃.

那么如何安全地删除与ac#program中的托管对象关联的外部c ++ dll中的非托管对象.

谢谢

安德鲁

Ada*_*son 8

任何托管对象的终结器几乎总是只能用作故障保护.作为一般规则,如果您有终结器逻辑,那么您的对象可能需要实现IDisposable.实现的基本模式IDisposable是(假设类名是MyClass):

public class MyClass : IDisposable
{
    private int extHandle;

    public MyClass()
    {
        extHandle = // get the handle
    }

    public void Dispose()
    {
        Dispose(true);

        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if(disposing)
        {
            // call dispose() on any managed objects you might have
        }

        // release the handle
    }

    ~MyClass()
    {
        Dispose(false);
    }
}
Run Code Online (Sandbox Code Playgroud)

这也意味着无论创建和使用此对象的任何代码都需要能够管理对象的生命周期.最简单的方法是将实例封装在一个using块中,如下所示:

using(MyClass c = new MyClass())
{
    // do things with c
}
Run Code Online (Sandbox Code Playgroud)

using块会自动调用Dispose该对象,因为它在块的末尾超出范围.当对象需要存在于单个函数之外时,事情当然会变得更加复杂.无论如何,每当对象完成时都Dispose需要调用.