您应该如何安全地创建和释放多个对象?
基本上,这类事情:
newOrderSource := TWebNewOrderSource.Create();
twData := TTWData.Create();
webData := TWebData.Create();
try
//do stuff
finally
newOrderSource.Free();
twData.Free();
webData.Free();
end;
在这种情况下,第二个和第三个create命令不安全,因为它们与数据库一起使用。我应该把所有Creates都放在try块中,并检查它们是否在我给它们免费打电话之前被分配了吗?
答案 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;