2009-05-29 26 views
9

Có bất kỳ rò rỉ bộ nhớ nào khi tôi ném ngoại lệ từ một hàm tạo như sau không?Ném ngoại lệ từ một hàm tạo trong .NET

class Victim 
{ 
    public string var1 = "asldslkjdlsakjdlksajdlksadlksajdlj"; 

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

Các đối tượng không thu thập được có được bộ thu gom rác thu thập không?

+0

liên quan Barely, nhưng mẹo hữu ích: Hãy cẩn thận về ngoại lệ ném trong constructor của Controls. Nó có thể phá vỡ các nhà thiết kế cho các điều khiển/hình thức. Tôi đã làm tròn nó bằng cách có một phương thức Initialise() và gọi nó ra bên ngoài (nhưng tôi không thích nó). –

Trả lời

23

Nói chung điều này là an toàn từ quan điểm của bộ nhớ không bị rò rỉ. Nhưng ném ngoại lệ từ một hàm tạo là nguy hiểm nếu bạn phân bổ tài nguyên không được quản lý trong loại. Lấy ví dụ sau

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

Lớp này sẽ rò rỉ bộ nhớ mỗi khi bạn cố gắng tạo ngay cả khi bạn sử dụng khối sử dụng. Ví dụ, điều này làm rò rỉ bộ nhớ.

using (var f = new Foo()) { 
    // Won't execute and Foo.Dispose is not called 
} 
+0

Cần phải làm cho nó rõ ràng rằng không chỉ cơ thể của tuyên bố sử dụng không thực thi ... nhưng phương thức .Dispose() của Foo không được gọi, vì không có cá thể nào được tạo ra để gọi .Dispose() on. – jrista

+0

@jrista cập nhật – JaredPar

+0

Tôi nghiêm túc đến muộn với bữa tiệc ở đây, nhưng sẽ không phải là cố gắng cuối cùng trong các nhà xây dựng sửa lỗi này mà không có vấn đề? – Gusdor

2

Có, bộ thu gom rác sẽ lấy lại tài nguyên được quản lý đã được cấp phát trong đối tượng. Nếu bạn đã khởi tạo bất kỳ tài nguyên không được quản lý nào, bạn sẽ cần phải dọn dẹp các tài nguyên đó theo cách thông thường.

1

Tùy thuộc vào những tài nguyên khác mà bạn đã có được trước khi ngoại lệ là thorwn. Tôi không nghĩ rằng ném ngoại lệ trong một nhà xây dựng là rất tốt, nhưng ném chúng trong finalizers hoặc vứt bỏ() là tồi tệ hơn nhiều.

+2

"ném chúng vào finalizers hoặc vứt bỏ() là tồi tệ hơn nhiều." Nó có thể được chấp nhận để ném vào Vứt bỏ - ví dụ FileStream sẽ ném nếu nó không thể tuôn ra Suối (ví dụ: do lỗi mạng). Tránh ném nếu bạn có thể, nhưng làm như vậy nếu bạn phải. Trong trường hợp FileStream, việc nuốt ngoại lệ sẽ nguy hiểm hơn nhiều so với việc ném, vì nó sẽ cho người gọi ấn tượng rằng tệp đã được viết thành công. – Joe

4

Vui, vì tôi đã giúp với similar question hôm qua.

Đó là một vấn đề lớn hơn nếu bạn có một loại dẫn xuất, bởi vì một số phần của kiểu dẫn xuất sẽ khởi tạo nhưng không phải là các phần khác. Từ góc độ bộ nhớ, nó không thực sự quan trọng, bởi vì người thu gom rác biết những gì ở đâu. Nhưng nếu bạn có bất kỳ tài nguyên không được quản lý (thực hiện IDisposable) mọi thứ có thể nhận được âm u.

9

Việc ném ngoại lệ từ một hàm tạo sẽ ổn nếu bạn không tạo tài nguyên không được quản lý. Tuy nhiên, nếu bạn tạo tài nguyên không được quản lý trong hàm tạo, toàn bộ phần thân của hàm tạo đó, bao gồm cả ném, phải được bao bọc trong một lần thử/nắm bắt. Để ăn cắp ví dụ tuyệt vời JaredPar của:

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

Sau đây bây giờ sẽ làm việc:

using (var f = new Foo()) { 
    // Won't execute, but Foo still cleans itself up 
} 
Các vấn đề liên quan