C++异常机制探讨

C++异常机制探讨,第1张

  引 言

  class="superseo">C++的异常机制为我们提供了更好的解决方法。异常处理的基本思想是:当出现错误时抛出一个异常,希望它的调用者能捕获并处理这个异常。如果调用者也不能处理这个异常,那么异常会传递给上级调用,直到被捕获处理为止。如果程序始终没有处理这个异常,最终它会被传到C++++运行环境,运行环境捕获后通常只是简单地终止这个程序。异常机制使得正常代码和错误处理代码清晰地划分开来,程序变得非常干净并且容易维护。

  但是如何合理地使用异常机制来达到预期的效果呢?MISRA C++给出了一些推荐的规则,帮助程序员更加合理、可靠地实现异常机制。下面将结合这些规则对异常机制进行简单的探讨。

  1 在恰当的场合使用恰当的特性

  MISRA C++对异常的第1条规则就是:

  规则15-0-1(不容讨论):异常机制只能用来处理错误。

  异常处理的本质是控制流程的转移,但异常机制是针对错误处理的,仅在代码可能出现异常的情况下使用,不能用来实现普通的流程转移。

  例如:

  

C++异常机制探讨,第2张

 

  语法不会阻止你这样做,但杀鸡焉用牛刀。这样不但会降低程序的可读性,也会带来更大的开销。实际上,用一个简单的if语句就可以实现上述逻辑。同样,出于程序流程的清晰性考虑的还有:

  规则15-0-3(强制):不允许通过goto或者switch语句跳转到try或catch语句块内。

  2 正确地抛出异常

  什么时候,什么地方,抛出什么样的异常,都是需要仔细考虑的。MISRA C++对此也作了相关规定。首先,来看一下抛出异常对象的类型中有哪些需要注意的地方。规则15-0-2(推荐):抛出的异常对象不应该是指针类型。

  如果抛出的异常对象是个指针类型,指向的是动态创建的对象,那么这个对象应该由哪个函数来负责销毁,什么时候销毁,都很不清楚。比如说,如果是在堆中建立的对象,那通常必须删除,否则会造成资源泄漏;如果不是在堆中建立的对象,通常不能删除,否则程序的行为将不可预测。

  规则15-1-2(强制):不能显式地把NULL作为异常对象抛出。

  因为throw(NULL)=tbrow(0),因此NULL会被当作整型捕获,而不是空指针常量,这可能与程序员的预期不一致。

  通常,很多函数都是基于funcTIon-try-block结构的,即函数体整个包含在一个函数try块中。而函数能抛出什么类型的异常对象,有以下规定:

  规则15-5-2(强制):如果一个函数声明时指定了具体的异常类型,那么它只能抛出指定类型的异常。

  规则15-4-1(强制):如果一个函数声明时指定了异常的类型,那么在其他编译单元里该函数的声明必须有同样的指定。

  函数的代码结构如下:返回值类型函数名(形参表)throw(类型名表){函数体}

  如果函数在声明时没有异常规范,那么它可以抛出任意类型的异常对象;如果异常类型为空,则表示不抛出任何类型异常。注意这两者之间的区别,前者指没有throw(类型名表)语句,而后者有throw(类型名表),只是类型名表为空。但如果声明时指定了异常的类型,那么它只能抛出指定类型的异常。

  另外,函数原型中的异常声明要与实现中的异常声明一致,否则会引起异常冲突。由于异常机制是在运行出现异常时才发挥作用的,因此如果函数的实现中抛出了没有在其异常声明列表中列出的异常,编译器也许不能检查出来。当抛出一个未在其异常声明列表里的异常类型时,unexpected()函数会被调用,默认会导致std::bad_excepTIon类型的异常被抛出。如果std::bad_excepTIon不在异常声明列表里,又会导致terminate()被调用,从而导致程序结束。

  对于什么时候能抛出异常,则有以下规定:

  规则15-3-1(强制):异常只能在初始化之后而且程序结束之前抛出。

  在执行main函数体之前,是初始化阶段,构造和初始化静态对象;在main函数返回后,是终止阶段,静态对象被销毁。在这两个阶段中如果抛出异常,会导致程序以不定的方式终止(这依赖于具体的编译器)。例如:

  

C++异常机制探讨,第3张

 

  在这个例子中,catch块只能捕获上面try块中的异常。如果在对象c的构造函数或析构函数中抛出异常,并不能被main里的catch块捕获,而且会导致程序终止。

  除了上述规则,还有以下两个规则需要注意:

  规则15-1-1(强制):throw语句中的表达式本身不能引发新的异常。

  如果在构造异常对象,或者计算赋值表达式时引发新的异常,那么新的异常会在本来要抛出的异常之前被抛出,这与程序员的预期不一致。

  规则15-1-3(强制):空的throw语句只能出现在catch语句块中。

  空的throw用来将捕获的异常再抛出,可以实现多个处理程序问异常的传递。然而,如果在catch语句外用,由于没有捕获到异常,也就没有东西可以再抛出,这样会导致程序以不定的方式终止(这依赖具体的编译器)。

  

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/dianzi/2713844.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-08-17
下一篇 2022-08-17

发表评论

登录后才能评论

评论列表(0条)

保存