Question

I am using Delphi 2010 and have a question re freeing objects.

Say I have code like below and I want to clear both TProduct and TPart if an exception occurs.

How do I free properly contained object TPart ?

//Clases are defined like this
TProduct = class(TRemotable)
private
  FName: String;
  FAge: Integer;
  FColor: String;
  FPart: TPart;  
published
  property Name: String read FName write FName;
  property Age: Integer read FAge write FAge;
  property Color: String read FString write FString;
  property Part: TPart read FPart write FPart;  
end;

TPart = class(TRemotable)
private
  FName: String;
  FColor: String;  
published
  property Name: String read FName write FName;
  property Color: String read FString write FString;
end;


//Then in a method, code will get info from database, create objects and fill them
function MyFunction: TProduct;
begin
  Result:=nil;

  query.Open;
  Result:=TProduct.Create;
  try
    try
      Result.Name:=query.FieldByName('NAME').AsString;
      Result.Age:=query.FieldByName('AGE').AsInteger;
      Result.Color:=query.FieldByName('COLOR').AsString;
      ...
      if (Result.Color='Blue') then
      begin
        Result.Part:=Part.Create;
        Result.Part.Name:='Bottle';
        Result.Part.Color:='Green';
      end;
    except
      on e: Exception do
      begin
        //If exception occurred, I want to make sure 
        //that both TProduct and TPart objects are freed properly
        FreeAndNil(Result); //works fine
        FreeAndNil(Result.Part); //<-- WON'T COMPILE - Get "Constant object cannot be passed as var parameter"
        Part.Free; //<--COMPILES but isn't FreeAndNil better?
      end;
    end;
  finally
    query.Close;
  end;
end;

I am not trying to redesign the code, just to make sure that if TPart is created, it is also freed?

Was it helpful?

Solution

The correct way is to have A take ownership of B and let A's destructor free B. That way, your exception handler only as to worry about freeing A, and it will free B if it was created before the exception was raised.

type
  ClassA = class
  public
    B: ClassB;
    destructor Destroy; override;
  end;

destructor ClassA.Destroy;
begin
  B.Free;
  inherited;
end;

var
  A: ClassA;
begin
  ...
  A := ClassA.Create;
  try
    ...
    A.B := ClassB.Create;
    ...
  except
    on e: Exception do
    begin
      FreeAndNil(A); // or A.Free;
      ...
    end;
  end;
  ...
end;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top