【问题标题】:MadExcept + try/finally block?MadExcept + try/finally 阻塞?
【发布时间】:2014-08-29 20:34:23
【问题描述】:

我有一些 delphi 代码,有点像这样:

try
  //some code
  //occasionally throws an exception here, for example an EIndexOutOfRangeException
  //more code...should get skipped if exception is thrown
finally
  // there may or may not be any important cleanup code here
end;

在这种情况下,除了跳出 try 块之外,不需要处理异常。因此,在将 mad-except 添加到项目以进行错误故障排除之前,此代码是“工作”的。但现在我收到了错误报告,因为 MadExcept 正在报告未捕获的异常。

相关问题,MadExcept triggers on try finally 表示 MadExcept 在这种情况下中断的行为是“预期的”,因为该异常没有“处理”。

我想澄清一下我的选项是什么,以防止在此代码运行时弹出 mad-except 对话框,无论是否有内部异常被抛出和忽略。

所以我认为没有开关来禁用 MadExcept 以阻止在 try/finally 块中处理未处理的异常是正确的吗?即使我想忽略它,我也需要明确地“捕获”异常?

我是否应该这样做(忽略任何异常):

try
  //some code
  //sometimes throws EIndexOutOfRangeException here
  //more code...should get skipped if exception is thrown
except do begin end;
end;

或者也许(忽略一个非常具体的例外):

try
  //some code
  //sometimes throws EIndexOutOfRangeException here
  //more code...should get skipped if exception is thrown
except on E : EIndexOutOfRangeException do begin end;
end;

或者可能需要:

try
  try
    //some code
    //sometimes throws EIndexOutOfRangeException here
    //more code...should get skipped if exception is thrown
  except on E : EIndexOutOfRangeException do begin end;
finally
  // some cleanup code
end;

如果这三个都是有效的解决方案,我是否应该出于某种原因更喜欢其中一个?

【问题讨论】:

  • 我看不出有什么理由不使用它们。这实际上取决于正在执行的代码。如果你需要清理一些东西,最后一个是你的选择。如果不是,那么问问自己是否需要以不同的方式处理特定类型的异常。无论如何,你只是忽略它,所以第一个就是你所需要的。
  • @Jerry:第一个不是必需的,实际上是有害的,因为它可以掩盖未预料到的异常。第二个例子是正确的。
  • @Mason 阅读您的回答后,是的,我知道这将是一个问题。
  • 为什么访问越界?你的代码坏了?最好修复它。
  • 是的,在一般情况下,最好先进行一些防御性编程并进行明确的边界检查,但这是在紧密循环中的一些性能关键代码中,结果超出了边界/invalid 非常罕见。在一般情况下跳过边界检查并处理在不常见情况下创建异常的代价会更快。

标签: delphi madexcept


【解决方案1】:

所以我认为没有开关来禁用 MadExcept 以阻止在 try/finally 块中处理未处理的异常是正确的?

是的。 try/finally 不是异常处理保证清理,无论是否发生异常。因此,try/finally 块与 MadExcept 等异常处理工具完全无关。

即使我想忽略它,我也需要明确地“捕获”异常?

是的。这就是异常的工作方式。它们沿着堆栈向下工作,直到找到捕获它们的处理程序。如果不存在这样的处理程序,则操作系统将其解释为崩溃并终止程序。 Delphi 的TApplication 对象在非常靠近调用堆栈底部的位置安装了一个处理程序,这样您的程序就不会崩溃,MadExcept 对此进行了挂钩,因此如果异常到达这一点,则会生成一个报告。

如果你想忽略一个异常,是的,你确实需要捕获它,因为你正在做的是正式的“通过在堆栈展开并忽略它的这一点上捕获它来处理异常”。关于“在堆栈展开时捕获它”的部分很重要,因为这意味着堆栈展开在该点停止并且程序恢复正常执行。如果您只是忽略它,(即,在您的代码中什么都不做,包括不安装异常处理程序),它将继续展开堆栈,一直到默认处理程序,无论您是否安装了 MadExcept。

是的,在这种情况下,示例 #2 是正确的做法。如果此时需要执行清理代码,示例 #3 也是有效的。但是示例 #1 在任何情况下都不应该这样做,因为这意味着您最终可能会忽略一个您没有预料到的异常,然后你最终会在你的程序中损坏并且你永远不会意识到它。

【讨论】:

  • 我会选择例如 3,但交换 try/finallytry/except。将try/finally 放在try/except 内,而不是相反。但无论哪种方式,是的,让except 捕获任何可以在那个时刻优雅地处理+丢弃的异常,这样 MadExcept 就不会看到它们。
  • @Remy 关键是要让执行流程正确。 madExcept 无关紧要。处理或不处理异常会改变程序的行为。更改执行的代码。必须做对。如果这意味着 madExcept 看到不应创建错误报告的未处理异常,则需要在 ME 未处理异常处理程序中进行处理。在低级别处理异常是改变 ME 处理方式的错误方法。
【解决方案2】:

在我看来,您对finally 的含义存在根本性的误解。

finally 块不会影响异常的传播。它只是确保finally 块将执行,即使引发了异常,或者正常的执行流程已被exitbreak 等修改。

去掉 try/finally,madExcept 仍然会报告程序引发了一个未处理的异常。

有一些方法可以告诉 madExcept 忽略某些异常。例如,一些例外应该是沉默的。典型的例子是EAbort。您可以使用RegisterExceptionHandler 来自定义处理未处理异常的方式。虽然,正如我将解释的那样,我怀疑这是否是您问题的解决方案。

接下来你需要做的是忘记 madExcept。您需要弄清楚如何处理此异常。你想在这里处理,还是需要让异常传播?只有你才能真正知道。但 madExcept 不是这里的驱动程序。必须推动您做出决定的是正确执行您的程序。是否应该处理异常以使您的程序正常运行?你必须先做对,然后再担心 madExcept。

如果需要在这里处理,那就选择性处理。不要捕获所有异常。这是绝对不行的。但如果你在这里处理它,问问自己这是否明智。代码未能执行某些操作。是否有一些后续代码依赖于该操作的成功?通过处理错误并按照您的建议忽略它,您将迫使所有后续代码对该操作的成功或失败感到矛盾。这对我来说似乎很可疑。

现在,EIndexOutOfRangeException 是个例外。这意味着您编写了类似A[i] 的内容,其中i 的值无效。我想不出一个可以接受的场景。因此,在我看来,您的程序包含错误并且只是使用了无效索引。您应该通过不越界访问来正确修复该错误。不要抑制异常,停止引发异常。

另一种看待这个的方式。您如何区分您当前的情况和写A[-i] 而不是A[i] 所产生的情况?抑制异常意味着您无法检测到这样的严重错误。

据我所知,最重要的是 madExcept 在您的代码中报告错误。你应该把 madExcept 当作你的朋友,听它说什么。它告诉您您的代码中存在应该修复的缺陷。

【讨论】:

  • 如果你没有看到我上面的其他评论,一般来说,我更喜欢事先进行显式边界检查以在我的编程中进行防御,但我碰巧选择描述的例子,它是一部分在一个紧密循环中的一些性能关键代码,其中数组查找失败很少见。在最常见的情况下,跳过对平均情况的边界检查并处理在查找失败的罕见情况下抛出异常的代价,最终会更快。
  • 我读的是问题而不是 cmets。无论如何,我仍然认为我的答案中的观点是站得住脚的。你的代码之前被破坏了。这与 madExcept 完全无关。如果您的代码的目的是让您处理此错误,那么您必须这样做。让它飘起来是不好的。我很失望你似乎没有理解我的观点。我认为你错过了学习重要知识的机会。
  • 我想我明白你的意思了,如果有 finally 但没有 catch("except on"),异常将继续传播,而且很可能从根本上说 不是 我想要发生的事情。在这种情况下,它应该有一个“EIndexOutOfRangeException 除外”块而不是 finally 块。
  • 首先要强调的是 madExcept 在这里不相关。重要的是程序的控制流,这是 madExcept 不会改变的。 finally 块与 except 完全不同。前者总是执行。无论是正常情况还是异常情况。后者仅在异常情况下执行。
  • 无论如何,我仍然非常确信您做错了什么。处理EIndexOutOfRangeException 异常并将它们视为正常是一种史诗般的代码气味。
猜你喜欢
  • 1970-01-01
  • 2012-09-08
  • 1970-01-01
  • 2011-11-05
  • 1970-01-01
  • 2015-09-01
  • 1970-01-01
  • 2011-10-07
相关资源
最近更新 更多