代码之家  ›  专栏  ›  技术社区  ›  Mik Kardash

从.NET中的构造函数引发异常

  •  11
  • Mik Kardash  · 技术社区  · 17 年前

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

    class Victim
    {
        public string var1 = "asldslkjdlsakjdlksajdlksadlksajdlj";
    
        public Victim()
        {
            //throw new Exception("oops!");
        }
    }
    

    故障对象将由垃圾收集器收集吗?

    5 回复  |  直到 14 年前
        1
  •  25
  •   JaredPar    17 年前

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

    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);
      }
    }
    

    即使使用using块,这个类也会在每次尝试创建时泄漏内存。例如,这会泄漏内存。

    using ( var f = new Foo() ) {
      // Won't execute and Foo.Dispose is not called
    } 
    
        2
  •  10
  •   jrista    17 年前

    如果没有创建非托管资源,则可以从构造函数中引发异常。但是,如果您确实在构造函数中创建了非托管资源,那么该构造函数的整个主体(包括throw)都应该包装在一个try/catch中。偷贾雷德帕的好榜样:

    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);
      }
    }
    

    现在可以使用以下方法:

    using ( var f = new Foo() ) {
      // Won't execute, but Foo still cleans itself up
    }
    
        3
  •  4
  •   Community Mohan Dere    9 年前

    很有趣,因为我帮了一个 similar question 就在昨天。

    如果您有一个派生类型,这是一个更大的问题,因为派生类型的某些部分将初始化,但其他部分不会初始化。从内存的角度来看,这并不重要,因为垃圾收集器知道在哪里。但是,如果您有任何非托管资源(实现IDisposable),事情可能会变得更糟。

        4
  •  2
  •   Rob    17 年前

    是的,垃圾收集器将回收对象中已分配的托管资源。如果您已经初始化了任何非托管资源,那么您将需要以正常方式清理这些资源。

        5
  •  1
  •   n8wrl    17 年前

    这取决于你在这个例外被索恩之前所获得的其他资源。我不认为在构造函数中抛出异常是很好的,但是在终结器或Dispose()中抛出异常更糟糕。

    推荐文章