从.NET中的构造函数中抛出异常

Mik*_*ash 11 .net memory garbage-collection exception

当我从如下构造函数中抛出异常时是否有任何内存泄漏?

class Victim
{
    public string var1 = "asldslkjdlsakjdlksajdlksadlksajdlj";

    public Victim()
    {
        //throw new Exception("oops!");
    }
}
Run Code Online (Sandbox Code Playgroud)

垃圾收集器是否会收集失败的对象?

Jar*_*Par 25

一般来说,从不泄漏内存的角度来看,这是安全的.但是,如果在类型中分配非托管资源,则从构造函数中抛出异常会很危险.以下面的例子为例

public class Foo : IDisposable { 
  private IntPtr m_ptr;
  public Foo() {
    m_ptr = Marshal.AllocHGlobal(42);
    throw new Exception();
  }
  // Most of Idisposable implementation ommitted for brevity
  public void Dispose() {
    Marshal.FreeHGlobal(m_ptr);
  }
}
Run Code Online (Sandbox Code Playgroud)

即使您使用using块,每次尝试创建时,此类都会泄漏内存.例如,这会泄漏内存.

using ( var f = new Foo() ) {
  // Won't execute and Foo.Dispose is not called
} 
Run Code Online (Sandbox Code Playgroud)


jri*_*sta 10

如果您没有创建非托管资源,那么从构造函数中抛出异常应该没问题.但是,如果您确实在构造函数中创建了非托管资源,那么构造函数的整个主体(包括throws)应该包装在try/catch中.偷走JaredPar的好例子:

public class Foo : IDisposable { 
  private IntPtr m_ptr;
  public Foo() {
    try
    {
        m_ptr = Marshal.AllocHGlobal(42);
        throw new Exception();
    }
    catch
    {
        Dispose();
        throw;
    }
  }
  // Most of Idisposable implementation ommitted for brevity
  public void Dispose() {
    Marshal.FreeHGlobal(m_ptr);
  }
}
Run Code Online (Sandbox Code Playgroud)

以下内容现在可以使用:

using ( var f = new Foo() ) {
  // Won't execute, but Foo still cleans itself up
}
Run Code Online (Sandbox Code Playgroud)