2008-12-09 256 views
1

结构化异常处理不好吗?什么是处理异常的正确方法?异常处理

编辑:在.NET中使用C#的异常处理。

我通常有一组特定的异常类(DivideByZeroException,ArrayTypeMismatchException)并且没有泛型“catch(Exception ex)”。

这个背后的思想是,我期望发生某些类型的异常,并在发生异常时定义特定的操作,并且意外的异常会升起界面(无论是Windows还是Web)。这是一个很好的做法吗?

+0

“结构化”是什么意思? – 2008-12-09 14:33:03

+0

如果你提到了一种语言,这将是一件好事,所以我们可以在详细和更好的情况下帮助你。 – GEOCHET 2008-12-09 14:33:06

回答

3

捕获语句+堆栈跟踪。在没有打印堆栈跟踪的情况下,如果没有捕获到异常,您或其他人将不得不再次检出该代码,并在发生错误并且日志文件为空或模糊时在Catch块中放置堆栈跟踪。

5

我不确定'结构化异常处理'是什么意思。

在异常处理中可以做的最糟糕的事情是“吞下”异常或者静静地处理异常。

不这样做:

try { 
    ... 
} 
catch (Exception e) { 
    //TODO: handle this later 
} 

这是很经常做出于懒惰让代码编译。如果您不知道如何处理特定级别的异常,请让该方法抛出异常,并且至少在顶部有一个catch all handler。以某种方式提供反馈(通过GUI,页面/电子邮件发送给支持人员,日志文件),以便问题最终得到解决。默默地捕捉异常几乎总是会导致稍后发生更大的问题,并且难以追踪。

1

我的建议:

不要捕捉异常,除非:

  • 如果不这样做会导致应用程序崩溃(例如,在事件处理程序)
    • 而在这的情况下,一定要记录异常,以便您知道发生了什么事情以及何时发生什么事情
  • 您可以对t并纠正这种情况(例如在调用偶尔会抛出异常的外部API时实现重试机制(请注意,不应该使用异常处理来控制程序流))
    • 而在这种情况下,只捕获您希望获得的特定异常类型抛出

捕获在尽可能高的水平异常意味着你得到最大的调用堆栈,当你经历的日志,并想看看初始动作触发的序列,这是非常有用的首先导致例外的事件。

1

这是一个复杂的话题......有这方面的书......但......有两种主要的异常处理类型......内联,其中处理潜在错误的代码与方法或例程将“正常”执行的代码以及结构化异常处理(其中代码位于其他地方)以及基础结构被设计为自动处理该异常处理代码意外事件(错误)发生......两者都有优势和劣势。 “内联”方法倾向于产生更加混乱的代码(带有错误代码),难以阅读和维护。但是,由于它不需要任何前期分析,所以它更容易生成。使用内联错误处理时,您经常会看到方法返回布尔值或数字“错误”代码,向调用方指明metjhod或例程是否成功。这消除了使例程“返回”有意义的业务价值或对象的“功能”语法(因为按惯例每个函数都必须返回错误代码)。使用结构化异常处理时,此问题没有实际意义。

结构化异常处理otoh通常很难做好,因为它需要事先分析例程或方法可能产生的错误以及该方法可以或应该对每个错误执行什么操作if它确实发生。

有一两件事是肯定的,不要在单一成分的两种方法混合...

0

我不是一个Windows程序员,但在使用结构化异常处理处理硬件异常之类的软件在我看来,例外意味着:

  • 您的代码在C++标准中产生了一些未定义或实现定义的行为(例如除以零)。
  • Windows定义在启用SEH的情况下,它会在此情况下引发异常。
  • 您正在使用这个事实来捕获异常和/或执行终止处理程序。

所以问题要问,IMO,主要有:

  • 是您的编程任务真正性质,即标准C++不能处理的? (或者只能通过明显低于硬件异常的方式来处理)。
  • 当你的代码变得非标准时你真的需要采取行动吗?
  • 您可以编写代码,以便它不会首先引发硬件异常?

如果答案为'是','是','否',则需要结构化的异常处理。否则,你可能可以避免它,在这种情况下,你可能想要。编写异常安全的代码非常棘手,所以异常保证越强大,你越能提供更好的结果。可能与SEH划分为零的代码不提供不保证,或许在重新设计时可能会导致呼叫者不提供数据,但可以这样做。但是如果一个函数由于其他原因而必须抛出异常,那么也可能将它们丢给硬件陷阱,这可能会让事情变得更糟。

一个值得注意的特例是内存分配。不确定.NET是否这样做,但是如果分配的虚拟地址空间不足,则Linux分配只会失败。物理内存在第一次使用时被提交,如果没有足够的硬件,会导致硬件异常。由于内存分配是假定在发生故障时抛出std :: bad_alloc,并且实现未能实现此标准的这一要求,所以可能是是因为在某些情况下将硬件异常转换为软件是正确的。但是,这种硬件异常可能会发生在意想不到的地方(包括您认为不太合适的例程),所以仍然可能无法妥善处理,这就是为什么linux核心转储而不是抛出。在实践中,完全初始化的任何东西都会导致其构造函数崩溃,这通常足够接近分配,而软件异常会变得有用。