如何在Delphi中安全地创建和释放多个对象

时间:2011-10-04 05:31:27

标签: delphi

您应该如何安全地创建和释放多个对象?

基本上,这类事情:

  newOrderSource := TWebNewOrderSource.Create();
  twData := TTWData.Create();
  webData := TWebData.Create();

  try
    //do stuff
  finally
    newOrderSource.Free();
    twData.Free();
    webData.Free();
  end;

在这种情况下,第二个和第三个create命令不安全,因为它们与数据库一起使用。我应该把所有Creates都放在try块中,并检查它们是否在我给它们免费打电话之前被分配了吗?

2 个答案:

答案 0 :(得分:15)

如果首先将nil分配给变量,可以使用一个try块执行此操作,如

newOrderSource := nil;
twData := nil;
webData := nil;
try
  newOrderSource := TWebNewOrderSource.Create();    
  twData := TTWData.Create();    
  webData := TWebData.Create();    

  //do stuff    
finally    
  webData.Free();    
  twData.Free();    
  newOrderSource.Free();    
end;    

这可行,因为Free()Self检查nil

答案 1 :(得分:10)

我确信每个人都知道,管理对象的标准方法是这样的:

A := TMyObject.Create;
try
  A.DoSomething;
finally
  A.Free;
end;

如果TMyObject.Create中存在异常,则会调用析构函数,然后引发异常。在这种情况下,A将不会分配给。

如果您有多个对象,则可以重复该模式:

A := TMyObject.Create;
try
  B := TMyObject.Create;
  try
    A.DoSomething;
    B.DoSomething;
  finally
    B.Free;
  end;
finally
  A.Free;
end;

这很快变得一团糟,因此也是问题。

标准技巧是利用Free可以安全地在nil对象引用上调用的事实。

A := nil;
B := nil;
try
  A := TMyObject.Create;
  B := TMyObject.Create;
  A.DoSomething;
  B.DoSomething;
finally
  B.Free;
  A.Free;
end;

这确实存在一个小弱点,即它不能适应B.Free中引发的异常,但将此视为可忽略的失败条件并非不合理。析构函数不应该引发异常。如果他们这样做,那么你的系统可能会被无法破坏。

随着更多对象的添加,上面的这种模式会变得有点混乱,所以我个人使用以下帮助方法。

procedure InitialiseNil(var Obj1); overload;
procedure InitialiseNil(var Obj1, Obj2); overload;
procedure InitialiseNil(var Obj1, Obj2, Obj3); overload;

procedure FreeAndNil(var Obj1); overload;
procedure FreeAndNil(var Obj1, Obj2); overload;
procedure FreeAndNil(var Obj1, Obj2, Obj3); overload;

实际上我的代码的版本包含更多参数。为了便于维护,此代码全部由简短的Python脚本自动生成。

这些方法以明显的方式实现,例如

procedure FreeAndNil(var Obj1, Obj2);
var
  Temp1, Temp2: TObject;
begin
  Temp1 := TObject(Obj1);
  Temp2 := TObject(Obj2);
  Pointer(Obj1) := nil;
  Pointer(Obj2) := nil;
  Temp1.Free;
  Temp2.Free;
end;

这允许我们像这样重写上面的示例:

InitialiseNil(A, B);
try
  A := TMyObject.Create;
  B := TMyObject.Create;
  A.DoSomething;
  B.DoSomething;
finally
  FreeAndNil(B, A);
end;