Delphi最终尝试了多个对象
我已经编写了这段代码:Delphi最终尝试了多个对象,delphi,Delphi,我已经编写了这段代码: 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:
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;
FD:=TList.Create;
FN:=TList.Create;
RemList:=TList.Create;
dati:=TStringList.Create;
尝试
尝试
//代码
除了
关于E:Exception-do
ShowMessage('值不正确。错误:'+E.Message);
结束;
最后
如果分配(dati),则
免费;
如果分配(FD),则
FD.免费;
如果分配(FN),则
FN.免费;
如果已分配(RemList),则
RemList.免费;
结束;
我正在使用firemonkey,所以在移动设备上运行时不会出现问题,因为ARC将管理生命周期。但当我在windows上时,这段代码安全吗
我已经读到,我不能把finally和catch都放在一起,所以我需要一个嵌套的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;
FD:=TList.Create;
尝试
FN:=TList.Create;
尝试
RemList:=TList.Create;
尝试
//等等。。。
最后
自由物;
结束;
最后
FN.免费;
结束;
最后
FD.免费;
结束;
在这里,我确信在任何情况下,我都会以安全的方式释放该对象,但代码很难阅读。我已经看到Marco Cantu在object pascal手册中提出了第二种方法,我理解这一点,但就我而言,我想避免它
我写的第一段代码会出错吗?如果我是你,我会使用第二段代码,因为你已经知道它更好;正如您所说,
TList.Create
(与其他构造函数一样)是“安全”的,但如果您总是假设角落后面有风险,那就更好了
请注意,当我说safe时,我的意思是如果您以这种方式调用它们,它们不会引发异常。异常可能发生在您可能无法预测的任何情况下,因此您确实应该通过try finally来保护代码
您还使用了Assigned()
,这是无用的。如果您查看Free
的实现,您会发现此代码(也有注释):
procedure-TObject.Free;
开始
//在ARC下,由于编译器进行翻译,因此实际上不会调用此方法
//该调用仅是实例变量的nil赋值,然后实例变量调用_InstClear
{$IFNDEF AUTOREFCOUNT}
如果Self为零,则
破坏;
{$ENDIF}
结束;
Assigned()
如果对象等于或不等于零,则返回true或false,因此基本上是在进行无用的双重检查。而嵌套的第二个代码try…最终
是通过书本方式处理对象构造/解构块,您还可以安全地将这些分组到单个try…finally
块中
一些事实将帮助我们压缩上述代码
- 构造函数总是可以抛出异常
- 析构函数决不能抛出异常。如果您处理的类破坏了可以抛出的析构函数,那么您将面临更大的问题
- 非托管局部变量未初始化-在包含对象引用的非ARC编译器中
// initialize object references so we can safely use them
FN := nil;
FD := nil;
RemList := nil;
dati := nil;
try
FD := TList<double>.Create;
FN := TList<double>.Create;
RemList := TList<double>.Create;
dati := TStringList.Create;
// do something
finally
dati.Free;
FD.Free;
FN.Free;
RemList.Free;
end;
//初始化对象引用以便安全使用它们
FN:=零;
FD:=零;
RemList:=零;
dati:=零;
尝试
FD:=TList.Create;
FN:=TList.Create;
RemList:=TList.Create;
dati:=TStringList.Create;
//做点什么
最后
免费;
FD.免费;
FN.免费;
RemList.免费;
结束;
如果任何构造函数失败,最后将执行块,并清除分配的所有引用。因为Free
在调用实例析构函数之前测试nil,所以在nil引用上调用它是安全的
上面介绍了如何编写安全构造/解构链。如果您的do something代码引发异常,您可以在内部使用try..except
块处理它,就像您现在正在做的一样
请记住,上面的代码不会处理构造函数抛出的异常,它只是执行适当的清理。如果您想处理可能的构造异常,您必须将上述代码包装到另一个
try…中,但块除外,或者让它们传播到更高的级别 是的,其中一个析构函数可能会引发跳过以下析构函数。那么?这安全吗?经验法则是不要假设它是安全的。我现在正在研究这两个特定的类,到目前为止,我没有看到在它们的析构函数中存在潜在异常的证据。但我可能错了,你永远不应该认为它是安全的。将它们嵌套在第二个示例中。编程的#1规则:假设一切都是错误,并确保正确处理它们。联系析构函数以避免引发错误。如果他们这样做了,你已经完蛋了,所以别担心。真正的问题是,如果其中一个构造函数引发,您将泄漏已经创建的对象。为什么你在免费打电话之前要测试分配的任务?自由已经做到了这一点。第二个是正确的做事方式。您可能不喜欢它,但除了
或
try..finally块之外,它是编写多个try..的正确方法。在我看来,它实际上比第一个更容易阅读,因为你可以清楚地遵循代码的流程。好吧,我不知道免费的东西。那么赋值是没有用的?@RaffaeleRossi好的,谢谢,我会设法格式化block 2,如果说这些构造函数不会引发,那就错了。每个人都可以提高。例如,内存不足。
// initialize object references so we can safely use them
FN := nil;
FD := nil;
RemList := nil;
dati := nil;
try
FD := TList<double>.Create;
FN := TList<double>.Create;
RemList := TList<double>.Create;
dati := TStringList.Create;
// do something
finally
dati.Free;
FD.Free;
FN.Free;
RemList.Free;
end;