何时以及如何使用异常处理?

时间:2010-12-22 05:14:05

标签: c++ windows exception exception-handling

我正在阅读有关异常处理的内容。我得到了一些关于异常处理的信息,但我有几个问题:

  1. 何时抛出异常?
  2. 我们可以使用返回值来表示错误,而不是抛出异常吗?
  3. 如果我通过try-catch块保护我的所有功能,是否会降低性能?
  4. 何时使用异常处理?
  5. 我看到一个项目,该项目中的每个函数都包含一个try-catch块(即整个函数内的代码被try-catch块包围)。这是一个好习惯吗?
  6. try-catch和__try __except有什么区别?

7 个答案:

答案 0 :(得分:76)

以下是我认为必须阅读的例外情况的全面指南:

例外和错误处理 - C++ FAQC++ FAQ lite

作为一般经验法则,当程序可以识别阻止执行的外部问题时,抛出异常。如果从服务器接收数据并且该数据无效,则抛出异常。磁盘空间不足?抛出一个例外。宇宙射线阻止你查询数据库?抛出一个例外。但是如果你从你自己的程序中得到一些无效数据 - 不要抛出异常。如果您的问题来自您自己的错误代码,最好使用ASSERT来防范它。需要进行异常处理以识别程序无法处理的问题并告诉用户有关用户的问题,因为用户可以处理它们。但是你的程序中的错误并不是用户可以处理的东西,所以程序崩溃不会比“answer_to_life_and_universe_and_everything的值不是42!这绝不应该发生!!!! 11”例外。

抓住一个例外,你可以用它做一些有用的事情,比如显示一个消息框。我喜欢在一个以某种方式处理用户输入的函数内部捕获异常。例如,用户按下按钮“Annihilate all hunams”,并且在annihilateAllHunamsClicked()函数内部有一个try ... catch块说“我不能”。即使摧毁hunamkind是一项复杂的操作,需要调用几十个和几十个函数,但只有一个尝试... catch,因为对于用户来说这是一个原子操作 - 一键式点击。每个函数中的异常检查都是多余和丑陋的。

另外,我不能建议熟悉RAII - 也就是说,确保所有初始化的数据都被自动销毁。这可以通过在堆栈上尽可能多地初始化来实现,并且当您需要在堆上初始化某些东西时,使用某种智能指针。当抛出异常时,堆栈上初始化的所有内容都将被自动销毁。如果你使用C风格的哑指针,当抛出异常时你会冒内存泄漏的风险,因为没有人在异常时清理它们(当然,你可以使用C风格的指针作为你的类的成员,但要确保它们是在析构函数中处理。)

答案 1 :(得分:12)

例外情况在各种情况下都很有用。

首先,有一些函数,其中计算前置条件的成本如此之高,如果发现不满足前置条件,则最好只进行计算并中止异常。例如,你不能反转一个奇异矩阵,但要计算它是否是单数你计算非常昂贵的行列式:它可能必须在函数内完成,所以只需“试一试”反转矩阵并报告如果你不能通过抛出异常就会出错。这基本上是一个例外,作为负前置条件用法。

然后还有其他情况,您的代码已经很复杂,并且很难在调用链中传递错误信息。这部分是因为C和C ++已经破坏了数据结构模型:还有其他更好的方法,但C ++不支持它们(例如在Haskell中使用monad)。这个用法基本上是我不能为正确做事而烦恼所以我会抛出异常:它不是正确的方法,但它很实用。

然后主要使用例外:报告何时外部前置条件或不变量(如内存或磁盘空间等资源)不可用。在这种情况下,您通常会终止程序或程序的主要部分,例外是传输有关问题的信息的好方法。 C ++异常是为报告错误而设计的,这会阻止程序继续

大多数现代语言(包括C ++)中使用的异常处理模型被已知打破。它太强大了。理论家现在已经开发出比完全开放的“扔任何东西”和“可能也许不会抓住它”模型更好的模型。此外,使用类型信息对异常进行分类并不是一个好主意。

所以你能做的最好的事情就是谨慎地抛出异常,当出现实际错误时,以及没有其他方法可以处理它捕获异常接近抛出点尽可能

答案 2 :(得分:4)

  

如果您的问题来自您自己的错误代码,最好使用ASSERT来防范它。需要进行异常处理以识别程序无法处理的问题并告诉用户有关用户的问题,因为用户可以处理它们。但是你的程序中的错误并不是用户可以处理的东西,所以程序崩溃不会说明什么

我不同意the accepted answer的这个方面。断言并不比抛出异常更好。如果异常仅适用于运行时错误(或“外部问题”),那么std::logic_error是什么?

逻辑错误几乎是定义阻止程序继续的条件。如果程序是逻辑构造,并且条件发生在该逻辑的域之外,那么它如何继续?你可以收集你们的意见,然后抛出异常!

这不像现有技术。 std::vector,仅举一例,抛出一个逻辑错误异常,即std::out_of_range。如果您使用标准库并且没有顶级处理程序来捕获标准异常 - 如果只调用什么()和退出(3) - 然后你的程序会突然沉默,终止。

一个断言宏是一个弱得多的守卫。没有恢复。除非,即你没有运行调试版本,在这种情况下, no execution 。断言宏属于计算比今天慢6个数量级的时代。如果您在测试逻辑错误时遇到麻烦,但在生产时不使用该测试,那么在生产中,您最好对代码充满信心!

标准库提供逻辑错误异常,并使用它们。它们存在是有原因的:因为逻辑错误发生,并且是例外。仅仅因为C特征断言没有理由依赖这种原始(并且可以说是无用的)机制,当异常处理工作时更好。

答案 3 :(得分:3)

最佳阅读

过去十五年来,人们一直在谈论异常处理。然而,尽管对如何正确处理例外达成了普遍共识,但仍然存在使用鸿沟。不正确的异常处理易于发现,易于避免,并且是一种简单的代码(和开发人员)质量指标。我知道绝对的规则会变得过于贴心或夸张,但作为一般规则,你不应该使用try / catch

http://codebetter.com/karlseguin/2010/01/25/don-t-use-try-catch/

答案 4 :(得分:2)

1.当有可能因此导致异常或问题之间的某处时,代码中包含异常检查。

2.仅在需要的情况下使用try-catch块。每个try-catch块的使用增加了额外的条件检查,这肯定会减少代码的优化。

3.我认为_try_except是一个有效的变量名....

答案 5 :(得分:0)

基本区别是:

  1. 为你做错误处理。
  2. 一个人就是你自己做的。

    • 例如,您有一个表达式可以0 divide error。使用try catch 1.将在发生错误时为您提供帮助。或者您需要if a==0 then..

    • 中的2.
    • 如果你没有尝试捕捉异常我不认为它更快,它只是绕过,如果error发生它将threw到外部处理程序。

  3. 交出自己意味着问题不会更进一步,在许多情况下在速度方面具有优势,但并非总是如此。

    建议:只需处理简单且逻辑上的情况。

答案 6 :(得分:-4)

许多C / C ++纯粹主义者完全不鼓励例外。主要的批评是:

  1. 它很慢 - 当然它并不是真的“慢”。但是,与纯c / c ++相比,存在相当多的开销。
  2. 它引入了错误 - 如果你没有正确处理异常,你可能会错过抛出异常的函数中的清理代码。
  3. 相反,每次调用函数时都要检查返回值/错误代码。

相关问题