相信大家都知道,管理对象的标准方式是这样的:
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;