我写了这段代码:
FD := TList<double>.Create;
FN := TList<double>.Create;
RemList := TList<double>.Create;
dati := TStringList.Create;
try
try
//code
except
on E : Exception do
ShowMessage('Incorrect values. Error: ' + E.Message);
end;
finally
if Assigned(dati) then
dati.Free;
if Assigned(FD) then
FD.Free;
if Assigned(FN) then
FN.Free;
if Assigned(RemList) then
RemList.Free;
end;
我用的是firemonkey,所以当我在移动的设备上运行时不会有问题,因为ARC会管理生命周期,但是当我在windows上运行时,这段代码安全吗?
我曾经读到过finally和catch all不能同时使用,所以我需要一个嵌套的try块,我想最好的方法是这样的:
FD := TList<double>.Create;
try
FN := TList<double>.Create;
try
RemList := TList<double>.Create;
try
//and so on...
finally
Rem.Free;
end;
finally
FN.Free;
end;
finally
FD.Free;
end;
在这里我确信我会在任何情况下以安全的方式释放对象,但是代码很难读。我在object pascal手册中看到Marco Cantu建议第二种方法,我理解它,但是在我的情况下我想避免它。
在我编写的第一个代码块中会发生错误吗?
2条答案
按热度按时间qyswt5oh1#
如果我是你,我会使用第二块代码,因为你已经知道它更好;
TList<double>.Create
(像其他构造函数一样)如您所说是“安全的”,但如果您总是假设在角落后面存在风险,那就更好了。注意,当我说 safe 时,我的意思是如果你用这种方式调用它们,它们不会引发异常。异常可能在你无法预测的任何情况下发生,所以你真的应该用try finally来保护代码。
你也在使用
Assigned()
,这是无用的。如果你看一下Free
的实现,你会发现这段代码(也是注解):Assigned()
返回true或false,判断对象是否等于nil,所以基本上是在做无用的双重检查。3j86kqsm2#
虽然第二段代码中嵌套了
try...finally
,但它最终是处理对象构造/解构块的一种“照本宣科”的方式,您也可以安全地将它们分组到单个try...finally
块中。一些事实,将帮助我们挤压以上代码.
因此,您的代码将如下所示:
如果任何构造函数失败,
finally
块将被执行,所有分配的引用将被清除。因为Free
在调用示例析构函数之前测试nil,所以在nil引用上调用它是安全的。上面介绍了如何编写安全的构造/解构链。如果你的 do something 代码抛出异常,你可以像现在这样用
try..except
块处理它。请记住,上面的代码不处理构造函数抛出的异常,它只是执行适当的清理。如果你想处理可能的构造异常,你必须将上面的代码 Package 在另一个
try...except
块中,或者让它们传播到更高的级别。