How should I free an array of objects in a Delphi

2019-04-06 07:54发布

问题:

Suppose my Delphi classes look like this:

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.

To properly clean up, what should go in the destructor? Is it enough to do SetLength(SubInfo,0), or do I need to loop through and free each TMySubInfo? Do I need to do anything at all?

回答1:

You need to loop through and free each created object.

You must know, that declaring a array of TMySubInfo doesn't actually create the objects. You have to create them later on.

I would use a TList instead for a more dynamic approach. You could even use a TObjectList that can free all its items when the list gets freed.



回答2:

You should free each item, like this

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


回答3:

You free the objects the same way you allocated them. If you assigned an element's value by calling the constructor of a class, then free the object referenced by that element.

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

That uses syntax introduced in Delphi 2005. If you have an older version, use an explicit loop-control variable:

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

You don't need to call SetLength at the end. A dynamic-array field like SubInfo gets released automatically when the object is destroyed. It works the same as interface, string, and Variant fields.



回答4:

Agreed with all the above suggestions, but I want to add an (admittedly somewhat anal) recommendation that you always call the FreeAndNil() procedure in preference to the Free method.

Sooner or later you will accidentally access an object that you have already freed. If you have the habit of FreeAndNil-ing everything, then you get an immediate a/v on the line that contains the problem. If you merely Free'd the object, you will likely get a mysterious and apparently unconnected failure some time later...

This might seem obsessive in the context of a destructor, as here. Ok, it is a bit, but either one does it everywhere or not at all.



回答5:

It is also anal, but Like to free in the reverse order to the creation, for example:

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

I view creation and destruction as parethesis () although it makes litte actual execution diference. Bri



回答6:

If you created the objects via constructor calls, you need to make calls to Free to free them. If not, you don't.



回答7:

For every new there should be a free.



回答8:

Can you not use Finalize?