2012-10-12 32 views
9

Ở đây tôi có một tình huống khó khăn, tôi đoán vậy. Tôi cần để có thể giải phóng một đối tượng là một lĩnh vực của một bản ghi. Tôi thường viết mã dọn dẹp trong destructor, nếu nó là một lớp. Nhưng vì các loại bản ghi không thể giới thiệu một "destructor", làm thế nào nó có thể gọi TObject (Field) .Free;?Làm thế nào để giải phóng một đối tượng trong hồ sơ?

Sẽ có hai loại sử dụng tôi dự đoán:

  1. Thay kỷ lục với một hình mới.

    Tôi nghĩ việc sử dụng này sẽ dễ triển khai. Vì các bản ghi là các kiểu giá trị và do đó chúng được sao chép khi gán, tôi có thể quá tải toán tử gán và giải phóng các đối tượng thuộc sở hữu của bản ghi cũ.

    (Edit: Chuyển nhượng quá tải đã không thể Đó là một thông tin mới đối với tôi ...)

  2. Thoát khỏi phạm vi nơi biến kỷ lục được xác định.

    Tôi có thể nghĩ ra một phương thức riêng để giải phóng các đối tượng và phương pháp này có thể được gọi là kích thích phạm vi theo cách thủ công. NHƯNG, đây là cùng một câu hỏi: Làm thế nào để làm cho nó nhiều hơn ghi? Hành vi này có loại cảm giác giống như một lớp học ...

Đây là một mẫu (và rõ ràng không việc sử dụng dự định):

TProperties = record 
    ... some other spesific typed fields: Integers, pointers etc.. 
    FBaseData: Pointer; 

    FAdditionalData: TList<Pointer>; 
    //FAdditionalData: array of Pointer; this was the first intended definition 
end; 

Giả sử,

FAdditionalData:=TList<Pointer>.Crete; 

gọi trong hàm tạo bản ghi hoặc theo cách thủ công trong phạm vi biến thể ghi bằng cách truy cập trường công khai như

procedure TFormX.ButtonXClick(Sender: TObject); 
var 
    rec: TProperties; 
begin 
    //rec:=TProperties.Create(with some parameters); 

    rec.FAdditionalData:=TList<Pointer>.Create; 

    //do some work with rec 
end; 

Sau khi ra khỏi phạm vi ButtonClick các rec là không còn nữa nhưng một TList vẫn giữ sự tồn tại của nó gây ra rò rỉ bộ nhớ ...

+1

Bài tập ghi không thể bị quá tải. – kludg

+0

Tôi đã không nhận thức được rằng (không bao giờ cần thiết trước), nhưng tôi đã học được nó ngay bây giờ :) Yeah, nó không thể được quá tải ... –

Trả lời

10

Nếu tất cả các bạn có trong hồ sơ là một tham chiếu đối tượng, sau đó bạn không thể có được trình biên dịch để giúp bạn. Bạn đang ở trong phí duy nhất của đời của đối tượng đó. Bạn không thể quá tải toán tử gán, và bạn không nhận được bất kỳ thông báo nào về quyết toán phạm vi.

Điều bạn có thể làm là thêm giao diện bảo vệ sẽ quản lý thời gian tồn tại của đối tượng.

TMyRecord = record 
    obj: TMyObject; 
    guard: IInterface; 
end; 

Bạn cần đảm bảo rằng TMyObject quản lý tuổi thọ của nó bằng cách tính tham chiếu. Ví dụ: lấy từ TInterfacedObject.

Khi bạn khởi kỷ lục bạn làm điều này:

rec.obj := TMyObject.Create; 
rec.guard := rec.obj; 

Tại thời điểm này, các guard lĩnh vực của hồ sơ bây giờ sẽ quản lý cuộc đời của đối tượng của bạn.

Trong thực tế, nếu bạn muốn đẩy ý tưởng này hơn nữa, bạn có thể xây dựng một lớp chuyên dụng để bảo vệ tuổi thọ của các đối tượng. Điều đó sau đó không còn hạn chế bạn thực hiện IInterface trên lớp học của bạn. Có rất nhiều ví dụ trên web minh họa kỹ thuật. Ví dụ: tôi cung cấp bài viết của Jarrod Hollingworth có tiêu đề Smart Pointers và Barry Kelly có tiêu đề Reference-counted pointers, revisited. Còn rất nhiều thứ nữa. Đó là một mẹo cũ!

Tuy nhiên, lưu ý rằng những gì bạn có ở đây là sự kết hợp kỳ lạ của loại giá trị và loại tham chiếu. Trên khuôn mặt của nó, hồ sơ là các loại giá trị. Tuy nhiên, hành động này giống như một loại tham chiếu. Nếu bạn có các trường khác trong bản ghi là các loại giá trị thì điều đó thậm chí còn khó hiểu hơn. Bạn sẽ cần phải rất ý thức về vấn đề này khi bạn làm việc với một bản ghi như vậy.

Khi đối mặt với nó, mà không biết nhiều hơn về thiết kế của bạn, tôi muốn có xu hướng khuyên bạn không nên đặt tham chiếu đối tượng trong hồ sơ. Chúng phù hợp hơn với các loại tham chiếu bên trong, tức là các lớp học.

+7

Tôi muốn đề nghị hàng đầu với đoạn cuối cùng đầu tiên. Đặt các lớp trong bản ghi là một con đường nhanh để mã lỗi nếu không phải là rất, rất cẩn thận với quản lý suốt đời. – afrazier

+0

Câu trả lời rất thông tin, cảm ơn ông Heffernan .. Tôi sẽ thử nghiệm những cách đó. Tôi cần cập nhật câu hỏi để rõ ràng hơn với thiết kế. Các trường đối tượng là ** TList ** s, nhưng có vẻ như tôi sẽ biến nó trở lại với những gì nó đã ở vị trí đầu tiên: ** mảng của con trỏ ** –

+1

Sử dụng mảng động giải quyết việc quản lý thời gian sống. Bạn có thể xem xét việc sử dụng 'TDynArray' xuất sắc từ Synopse để làm cho việc sử dụng mảng động trở nên dễ dàng hơn. –

3

Tôi nhớ rằng ai đó đã tạo một lớp có tên là TLifetimeWatcher. Về cơ bản, nó trông giống như:

TLifetimeWatcher = class(TInterfacedObject) 
private 
    fInstance: TObject; 
    fProc: TProc; 
public 
    constructor Create(instance: TObject); overload; 
    constructor Create(instance: TObject; proc: TProc); overload; 
    destructor Destroy; override; 
end; 

// The (dọn dẹp) proc sẽ được thực hiện trong destructor nếu được giao, nếu không dụ sẽ được giải phóng bằng cách gọi phương pháp miễn phí.

+0

Đây là cách tiếp cận cơ bản được nêu trong câu trả lời của tôi. Nếu không thực hiện, nó không được sử dụng nhiều. –

+2

'Ai đó' là Barry Kelly - http://blog.barrkel.com/2008/09/smart-pointers-in-delphi.html – kludg

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