5

我有一个名为“CTransferManaged”的 C++/CLI 类,并实现了终结器和析构函数:

CTransferManaged::~CTransferManaged()
{
    this->!CTransferManaged();
}
CTransferManaged::!CTransferManaged()
{
    //Clean up resources... 
}

该类被一个名为“CTransfer”的 C# 类包裹,其中包含一个 CTransferManaged 类型的对象 m_transfer。

如果这个类的析构函数只清除对对象 m_transfer 的引用,我可以看到析构函数被调用(断点被命中):

~CTransfer()
{
    m_transfer = null; //breakpoint on this line
}

如果我调用 m_transfer 对象的 Dispose() 函数而不更改任何其他内容,则不再调用析构函数(断点不再命中)。任何猜测为什么?

~CTransfer()
{
    m_transfer.Dispose(); //breakpoint on this line
    m_transfer = null;
}

我想手动调用 Dispose(),因为我发现如果我不手动调用 Dispose,C++/CLI 对象 (m_transfer) 的资源不会被正确清理。目前我不知道具体原因。

为什么 CTransfer(C# 类)的析构函数在调用 CTransferManaged::Dispose() (C++/CLI) 时不再被调用?

4

2 回答 2

0

Disposing 和 Finalizing 的典型模式是,当您调用 Dispose 时,应该抑制终结器。Dispose 旨在在执行后立即清除资源,而终结器旨在在垃圾收集器收集类时清除资源......两者都旨在做同样的事情(释放非托管资源),所以如果你调用Dispose,调用终结器将是多余和不必要的,并且还会导致对象的生存时间比它需要的更长,因为它会在被收集和销毁之前首先放置在终结器队列中。这会导致创建和处置许多对象的高访问应用程序的内存管理不佳。因此,C# 中的大多数 Dispose 方法都会调用:

GC.SuppressFinalize(this);

这告诉垃圾收集器不要做终结器。这种模式被广泛使用,并且很可能在您的非托管类中使用。这可能就是 Dispose 调用消除析构函数的原因。

于 2013-06-06T15:49:30.300 回答
0

C#析构函数只能被垃圾收集器调用,不能直接调用。

作为 IDisposalbe 接口的一部分的 Dispose 只能手动调用,它不会触发析构函数。

不要依赖析构函数,而是尝试实现 iDisposabe 并直接调用 Dispose 方法并将代码放在那里。

如果 Resource 类包含应释放的嵌入对象,则 C# 需要此模式:

// C#
public class Resource : IDisposable
{
   private EmbeddedResource embedded;

   public Resource()
   {
      Console.WriteLine("allocating resource");
      embedded = new EmbeddedResource();
   }

   ~Resource()
   {
      Dispose(false);
   }

   protected virtual void Dispose(bool disposing)
   {
      Console.WriteLine("release resource");
      if (disposing)
      {
         embedded.Dispose();
      }
   }

   public void Dispose()
   {
      Dispose(true);
   }
}
于 2013-06-06T15:48:24.573 回答