如何释放另一个对象中包含的对象

时间:2014-04-21 20:06:23

标签: delphi oop delphi-2010

我正在使用Delphi 2010并且有一个问题是重新释放对象。

假设我有类似下面的代码,如果发生异常,我想清除TProduct和TPart。

如何释放正确包含的对象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;

我不是要重新设计代码,只是为了确保如果创建了TPart,它也会被释放?

1 个答案:

答案 0 :(得分:5)

正确的方法是让A获得B的所有权,让A的析构函数免费B。这样,您的异常处理程序只会担心释放A,如果它是在引发异常之前创建的,它将释放B

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;