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

Eri*_*c G 11 delphi

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

基本上,这种事情:

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

  try
    //do stuff
  finally
    newOrderSource.Free();
    twData.Free();
    webData.Free();
  end;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,第二个和第三个create命令不安全,因为它们与数据库一起使用.我是否应该将所有Creates放入try块并检查它们是否在我免费呼叫之前被分配了?

chu*_*ckj 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;    
Run Code Online (Sandbox Code Playgroud)

这工作,因为Free()检查Selfnil.

  • 我一直都在使用这个,但是关于安全性,你应该注意到,与OP的原始代码相比,这可以保护你免受任何一个构造函数中引发的异常的影响,但**不会**在释放对象时引发的异常.如果你对此有所了解,你唯一的选择就是拥有与对象一样多的try/finally(或让它们实现接口并让它们超出范围). (6认同)
  • 这也有效,并删除了一个不需要的任务但在这种情况下我赞成简单性和一致性,因为如果"do stuff"调用到数据库中,保存赋值很可能会有很大的不同. (2认同)

Dav*_*nan 10

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

A := TMyObject.Create;
try
  A.DoSomething;
finally
  A.Free;
end;
Run Code Online (Sandbox Code Playgroud)

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

当您有多个对象时,可以重复该模式:

A := TMyObject.Create;
try
  B := TMyObject.Create;
  try
    A.DoSomething;
    B.DoSomething;
  finally
    B.Free;
  end;
finally
  A.Free;
end;
Run Code Online (Sandbox Code Playgroud)

这很快变得一团糟,因此问题.

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

A := nil;
B := nil;
try
  A := TMyObject.Create;
  B := TMyObject.Create;
  A.DoSomething;
  B.DoSomething;
finally
  B.Free;
  A.Free;
end;
Run Code Online (Sandbox Code Playgroud)

这确实有一个小的弱点,即它不能适应异常,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;
Run Code Online (Sandbox Code Playgroud)

事实上,我的代码具有更多参数的版本.为了便于维护,此代码全部由简短的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;
Run Code Online (Sandbox Code Playgroud)

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

InitialiseNil(A, B);
try
  A := TMyObject.Create;
  B := TMyObject.Create;
  A.DoSomething;
  B.DoSomething;
finally
  FreeAndNil(B, A);
end;
Run Code Online (Sandbox Code Playgroud)