views:

1836

answers:

8

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  A: 

For every new there should be a free.

dwc
or Create in Delphi
Gerry
+8  A: 

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.

Vegar
Yep, I am calling TMySubInfo.Create in a loop to create them. Once created however, I don't need to add or remove any - which is why I chose a simple array.
Blorgbeard
Also, assuming that I free them in a loop, do I need to SetLength(0) as well, afterwards?
Blorgbeard
There is no need to call SetLength. Dynamic arrays are automatically cleaned up once there reference count goes to 0.
Gerry
What about static arrays ...how do I clean that up?
nomad311
+2  A: 

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

anon
+6  A: 

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;
Cesar Romero
SetLength(SubInfo, 0); is optional, but yes good code.
Jim McKeeth
+4  A: 

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.

Rob Kennedy
+3  A: 

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.

willw
A: 

Can you not use Finalize?

Urf
Finalize won't Free referenced objects or Dispose New'ed pointers etc.
Ulrich Gerhardt
A: 

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

Brian Frost