Delphi 最后尝试多个对象

qnyhuwrf  于 2022-12-18  发布在  其他
关注(0)|答案(2)|浏览(138)

我写了这段代码:

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建议第二种方法,我理解它,但是在我的情况下我想避免它。
在我编写的第一个代码块中会发生错误吗?

qyswt5oh

qyswt5oh1#

如果我是你,我会使用第二块代码,因为你已经知道它更好; TList<double>.Create(像其他构造函数一样)如您所说是“安全的”,但如果您总是假设在角落后面存在风险,那就更好了。
注意,当我说 safe 时,我的意思是如果你用这种方式调用它们,它们不会引发异常。异常可能在你无法预测的任何情况下发生,所以你真的应该用try finally来保护代码。
你也在使用Assigned(),这是无用的。如果你看一下Free的实现,你会发现这段代码(也是注解):

procedure TObject.Free;
begin
// under ARC, this method isn't actually called since the compiler translates
// the call to be a mere nil assignment to the instance variable, which then calls _InstClear
{$IFNDEF AUTOREFCOUNT}
  if Self <> nil then
    Destroy;
{$ENDIF}
end;

Assigned()返回true或false,判断对象是否等于nil,所以基本上是在做无用的双重检查。

3j86kqsm

3j86kqsm2#

虽然第二段代码中嵌套了try...finally,但它最终是处理对象构造/解构块的一种“照本宣科”的方式,您也可以安全地将它们分组到单个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;

如果任何构造函数失败,finally块将被执行,所有分配的引用将被清除。因为Free在调用示例析构函数之前测试nil,所以在nil引用上调用它是安全的。
上面介绍了如何编写安全的构造/解构链。如果你的 do something 代码抛出异常,你可以像现在这样用try..except块处理它。
请记住,上面的代码不处理构造函数抛出的异常,它只是执行适当的清理。如果你想处理可能的构造异常,你必须将上面的代码 Package 在另一个try...except块中,或者让它们传播到更高的级别。

相关问题