我正在阅读有关异常处理的信息。我获得了有关什么是异常处理的一些信息,但是我有几个问题:
- 什么时候抛出异常?
- 除了抛出异常,我们还可以使用返回值来指示错误吗?
- 如果我通过try-catch块保护所有功能,会不会降低性能?
- 什么时候使用异常处理?
- 我看到了一个项目,该项目中的每个函数都包含一个try-catch块(即,整个函数内的代码被try-catch块包围)。这是一个好习惯吗?
- try-catch和__try __except有什么区别?
我正在阅读有关异常处理的信息。我获得了有关什么是异常处理的一些信息,但是我有几个问题:
Answers:
这是关于异常的非常全面的指南,我认为这是必读的:
异常和错误处理-C ++ FAQ或C ++ FAQ Lite
作为一般经验法则,当程序可以识别外部妨碍执行的问题。如果您从服务器接收到数据并且该数据无效,则引发异常。磁盘空间不足?引发异常。宇宙射线会阻止您查询数据库?引发异常。但是,如果您从自己的程序中获取了一些无效数据,请不要抛出异常。如果您的问题来自您自己的错误代码,则最好使用ASSERT进行防范。需要异常处理来识别程序无法处理的问题并告诉用户有关的问题,因为用户可以处理它们。但是程序中的错误不是用户可以处理的,因此程序崩溃将告诉我们“ answer_to_life_and_universe_and_everything的值不是42!这永远不会发生!!! 11”异常。
捕获一个异常,您可以在其中执行一些有用的操作,例如显示一个消息框。我更喜欢在某个以某种方式处理用户输入的函数中捕获异常。例如,用户按下按钮“消除所有饥饿感”,并且在annihilateAllHunamsClicked()函数内部,有一个try ... catch块说“我不能”。尽管hunamkind的an灭是一项复杂的操作,需要调用数十个函数,但只有一个try ... catch,因为对于用户而言,这是一个原子操作-单击一次按钮。每个功能中的异常检查都是多余且丑陋的。
另外,我不建议您足够熟悉RAII-也就是说,要确保初始化的所有数据都被自动销毁。这可以通过在堆栈上尽可能多地初始化来实现,并且当您需要在堆上初始化某些内容时,请使用某种智能指针。引发异常时,堆栈上所有初始化的内容都会自动销毁。如果使用C风格的哑指针,则在引发异常时会冒内存泄漏的风险,因为没有人可以清除异常(当然,您可以将C风格的指针用作类的成员,但请确保它们是在析构函数中得到照顾)。
fclose
!)。它不会给您完整的堆栈跟踪信息。
异常在各种情况下都很有用。
首先,在某些函数中,计算前提条件的成本如此之高,最好只进行计算,如果发现不满足前提条件,则异常终止。例如,您不能反转奇异矩阵,但是要计算奇异矩阵,您需要计算非常昂贵的行列式:无论如何都可能必须在函数内部完成,因此只需“尝试一下”即可反转矩阵并报告如果无法通过引发异常则返回错误。作为否定的前提条件使用,这基本上是一个例外。
在其他情况下,您的代码已经很复杂,并且很难将错误信息传递给调用链。部分原因是C和C ++的数据结构模型已损坏:还有其他更好的方法,但是C ++不支持它们(例如在Haskell中使用monad)。基本上,我不会理会这种用法,所以我会抛出一个例外:它不是正确的方法,但是很实用。
然后是例外的主要用途:在外部先决条件或不变量(例如内存或磁盘空间等足够的资源)不可用时进行报告。在这种情况下,您通常将终止程序或其主要子节,并且该异常是传输有关问题的信息的好方法。C ++异常旨在报告导致程序无法继续执行的错误。
众所周知,包括C ++在内的大多数现代语言中使用的异常处理模型已被破坏。它太强大了。与完全开放的“抛出任何东西”和“也许可能不抓到它”模型相比,理论家现在已经开发出了更好的模型。另外,使用类型信息对异常进行分类不是一个好主意。
因此,您可以做的最好的事情是:在出现实际错误时,并且在没有其他方法可以处理异常并捕获尽可能接近抛出点的异常时,谨慎地抛出异常。
如果您的问题来自您自己的错误代码,则最好使用ASSERT进行防范。需要异常处理来识别程序无法处理的问题,并告知用户有关的问题,因为用户可以处理它们。但是程序中的错误是用户无法处理的,因此程序崩溃并不能说明什么
我不同意接受的答案的这一方面。断言并不比抛出异常更好。如果异常仅适用于运行时错误(或“外部问题”),那么这有什么std::logic_error
用?
从定义上讲,逻辑错误几乎是阻止程序继续的那种情况。如果程序是逻辑结构,并且条件发生在该逻辑的范围之外,那么该程序如何继续?尽可能收集您的输入,并抛出异常!
这就像没有现有技术一样。 std::vector
,仅举一个,抛出一个逻辑错误异常,即std::out_of_range
。如果您使用标准库并且没有顶级处理程序来捕获标准异常-如果仅调用what()并退出(3)-那么您的程序将遭受突然的静默,终止。
断言宏的防护性要弱得多。无法恢复。除非,也就是说,您没有运行调试版本,否则将无法执行。断言宏属于计算比现在慢6个数量级的时代。如果您要麻烦测试逻辑错误,但是在生产中不使用该测试,则最好对代码充满信心!
标准库提供逻辑错误异常,并采用它们。它们之所以存在是有原因的:因为发生逻辑错误,并且是异常情况。当异常可以更好地处理工作时,仅因为C功能断言就没有理由依赖这种原始的(可能是无用的)机制。
最好的阅读
在过去的十五年中,关于异常处理的讨论很多。但是,尽管就如何正确处理异常达成了普遍共识,但用法上的分歧仍然存在。错误的异常处理很容易发现,避免,并且是简单的代码(和开发人员)质量指标。我知道绝对规则会以谨慎或夸张的方式出现,但作为一般规则,您不应该使用try / catch
http://codebetter.com/karlseguin/2010/01/25/don-t-use-try-catch/
try
/ catch {}
?
1.如果有可能在结果之间或问题之间的某个地方出现异常,则代码中将包含异常检查。
2.仅在需要的情况下使用try-catch块。每个try-catch块的使用增加了额外的条件检查,这肯定会减少代码的优化。
3.我认为_try_except是有效的变量名....
许多C / C ++纯粹主义者完全阻止异常。主要批评是:
而是在每次调用函数时检查返回值/错误代码。