Создание исключений из конструктора в .NET - PullRequest
11 голосов
/ 29 мая 2009

Есть ли утечки памяти при выдаче исключения из конструктора, подобного следующему?

class Victim
{
    public string var1 = "asldslkjdlsakjdlksajdlksadlksajdlj";

    public Victim()
    {
        //throw new Exception("oops!");
    }
}

Будут ли сбойные объекты собираться сборщиком мусора?

Ответы [ 5 ]

25 голосов
/ 29 мая 2009

В целом это безопасно с точки зрения не утечки памяти. Но бросать исключения из конструктора опасно, если вы выделяете неуправляемые ресурсы в типе. Возьмите следующий пример

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
} 
10 голосов
/ 29 мая 2009

Бросать исключения из конструктора должно быть хорошо, если вы не создали неуправляемых ресурсов. Однако, если вы создаете неуправляемые ресурсы в конструкторе, все тело этого конструктора, включая throw, должно быть заключено в 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);
  }
}

Теперь будет работать следующее:

using ( var f = new Foo() ) {
  // Won't execute, but Foo still cleans itself up
}
4 голосов
/ 29 мая 2009

Забавно, потому что я помог с похожим вопросом только вчера.

Это большая проблема, если у вас есть производный тип, потому что некоторые части производного типа будут инициализированы, но не другие. С точки зрения памяти это не имеет большого значения, потому что сборщик мусора знает, что и где. Но если у вас есть какие-то неуправляемые ресурсы (реализуйте IDisposable), все может стать мутным.

2 голосов
/ 29 мая 2009

Да, сборщик мусора вернет управляемые ресурсы, уже выделенные в объекте. Если вы инициализировали какие-либо неуправляемые ресурсы, вам нужно будет их самостоятельно очистить обычным способом.

1 голос
/ 29 мая 2009

Это зависит от того, какие другие ресурсы вы приобрели, прежде чем будет использовано исключение. Я не думаю, что бросать исключения в конструкторе - это здорово, но бросать их в финализаторы или dispose () намного хуже.

...