2009-02-12 27 views
9

Giả sử lớp Delphi của tôi trông như thế này:Làm thế nào tôi có thể giải phóng một mảng các đối tượng trong một destructor Delphi 7?

interface 
type 

    TMySubInfo = class 
    public 
     Name : string; 
     Date : TDateTime; 
     Age : Integer; 
    end; 

    TMyInfo = class 
    public 
     Name : string; 
     SubInfo : array of TMySubInfo; 
     destructor Destroy; override; 
    end; 

implementation 

    destructor TMyInfo.Destroy; 
    begin 
     // hmmm.. 
    end; 

end. 

Để đúng cách dọn dẹp, những gì nên đi trong destructor? Có đủ để làm SetLength(SubInfo,0) hoặc tôi có cần lặp lại và miễn phí cho mỗi TMySubInfo không? Tôi có cần làm gì không?

Trả lời

12

Bạn cần lặp lại và giải phóng từng đối tượng đã tạo.

Bạn phải biết, việc khai báo một mảng TMySubInfo không thực sự tạo đối tượng. Bạn phải tạo chúng sau này.

Tôi sẽ sử dụng TList thay cho một cách tiếp cận năng động hơn. Bạn thậm chí có thể sử dụng một TObjectList có thể giải phóng tất cả các mục của nó khi danh sách được giải phóng.

+0

Đúng, tôi đang gọi TMySubInfo.Create trong một vòng lặp để tạo chúng. Tuy nhiên, khi đã tạo, tôi không cần thêm hoặc xóa bất kỳ thứ gì - đó là lý do tại sao tôi chọn một mảng đơn giản. – Blorgbeard

+0

Ngoài ra, giả sử rằng tôi giải phóng chúng trong một vòng lặp, tôi có cần SetLength (0) không, sau đó? – Blorgbeard

+3

Không cần phải gọi SetLength. Mảng động được tự động làm sạch lên một khi có số tham chiếu đi đến 0. –

2

Đối với mỗi mới, sẽ có miễn phí.

+1

hoặc Tạo trong Delphi –

+0

Thực ra, không phải ở Delphi.Đầu tiên, các giao diện được tính tham chiếu và các đối tượng được gán cho chúng sẽ tự động được giải phóng. Thứ hai, các bản ghi có thể được khởi tạo bằng cách sử dụng 'Tạo', nhưng bạn không' Free' chúng. – user

3

Nếu bạn đã tạo các đối tượng thông qua các cuộc gọi hàm tạo, bạn cần thực hiện cuộc gọi đến Miễn phí để giải phóng chúng. Nếu không, bạn thì không.

9

Bạn nên giải phóng từng hạng mục, như thế này

destructor TMyInfo.Destroy; 
var 
    I: Integer; 
begin 
    for I:= Low(SubInfo) to High(SubInfo) do 
    SubInfo[I].Free; 
    SetLength(SubInfo, 0); 
    inherited; 
end; 
+3

SetLength (SubInfo, 0); là tùy chọn, nhưng có mã tốt. –

6

Bạn giải phóng các đối tượng giống như cách bạn phân bổ cho họ. Nếu bạn đã gán giá trị của một phần tử bằng cách gọi hàm khởi tạo của một lớp, thì hãy giải phóng đối tượng được tham chiếu bởi phần tử đó.

destructor TMyInfo.Destroy; 
var 
    info: TMySubInfo; 
begin 
    for info in SubInfo do 
    info.Free; 
    inherited; 
end; 

Đó sử dụng cú pháp giới thiệu trong Delphi 2005. Nếu bạn có một phiên bản cũ, sử dụng một biến vòng lặp kiểm soát rõ ràng:

var 
    i: Integer; 
begin 
    for i := 0 to High(SubInfo) do 
    SubInfo[i].Free; 

Bạn không cần phải gọi SetLength ở cuối. Trường mảng động như SubInfo được phát hành tự động khi đối tượng bị hủy. Nó hoạt động giống như các trường giao diện, chuỗi và biến thể.

5

Đồng ý với tất cả các đề xuất ở trên, nhưng tôi muốn thêm đề xuất (thừa nhận hơi hậu môn) rằng bạn luôn gọi thủ tục FreeAndNil() tùy theo phương thức Miễn phí.

Sớm hay muộn bạn sẽ vô tình truy cập một đối tượng mà bạn đã giải phóng. Nếu bạn có thói quen FreeAndNil-ing tất cả mọi thứ, sau đó bạn nhận được một/v ngay lập tức trên dòng có chứa vấn đề. Nếu bạn chỉ đơn thuần là Free'd đối tượng, bạn sẽ có thể nhận được một thất bại bí ẩn và dường như không kết nối một thời gian sau đó ...

Điều này có vẻ ám ảnh trong bối cảnh của một destructor, như ở đây. Ok, nó là một chút, nhưng một trong hai không nó ở khắp mọi nơi hay không ở tất cả.

0

Bạn không thể sử dụng Finalize?

+0

Hoàn thành sẽ không tham chiếu các đối tượng miễn phí hoặc Vứt bỏ các con trỏ mới… –

4

Nó cũng là hậu môn, nhưng Giống như để giải phóng theo thứ tự ngược lại để tạo ra, ví dụ:

For I := List.Count-1 downto 0 do 
    List[I].Free; 

tôi xem sáng tạo và hủy diệt như parethesis() mặc dù nó làm cho litte diference thực hiện thực tế. Bri

Các vấn đề liên quan