异常机制的使用
根据上述规则,典型的try-catch的结构示例如下:本文引用地址://m.amcfsurvey.com/article/202581.htm
细心的读者也许会发现,上面例子中是通过引用来捕获类的对象。当异常对象类型为某个类时,有3种方式传递到catch子句里:指针、传值和引用。也许大家首先想到的是指针,指针的确是效率很高的工具,而且不涉及到对象拷贝。但不要忘了,前面的规则15-0-2中明确指出,抛出的异常对象不应该是指针类型。而对于传值和引用,在MISRA C++中给出的规定是:通过引用捕获异常。
规则15-3-5(强制):若异常对象为类的对象时,应该通过引用来捕获。
通过值传递,不但会增加拷贝对象的开销,而且还会出现“退化”问题。所谓“退化”是指:如果异常对象是一个派生类对象,但被作为基类捕获,那么只有基类的函数(包括虚函数)能被调用,派生类中增加的数据成员都不能被访问。通过引用捕获则没有这个问题。下面的例子具体地说明了“退化”问题:
鉴于类的构造函数和析构函数的特殊性,还有两点需要注意。
规则15-3-3(强制):如果类的构造函数和析构函数是function-try-block结构的,在catch处理程序中不能引用该类或其基类的非静态成员。
这种行为的后果是不定的。比如说,当构造对象分配内存时抛出了异常,这时该对象本身还不存在,访问其成员也就出错。相反,在析构函数里,可能在异常处理程序执行前该对象已被成功销毁了,也就无从访问其成员了。而类的静态成员则没有上述问题。
规则15-5-1(强制)。类的析构函数退出后不能还有未处理的异常。
当异常抛出时,会进行栈展开。如果在某个析构过程中引发没有被处理的异常,程序将会以不定的方式终止。析构函数抛出异常的问题在很多C++的书中都有讨论,概括来说:析构函数应尽可能地避免抛出异常,如果的确无法避免,则析构函数自己应该包含处理所有可能抛出的异常的代码。
4 小 结
异常机制是C++崭新而高级的特性之一。与其他C++特性一样,C++标准并没有规定应该如何来实现异常机制,这依赖于具体的编译器。异常机制是有代价的,它会增加代码大小和运行开销。以VC++为例,异常处理是通过在函数调用栈里增加许多相关的数据结构来实现的,感兴趣的读者可以查看相关资料,这里不再进一步讨论;而且异常处理是在操作系统的协助下,由C++编译器和运行时异常处理库共同完成的。如何合理地使用异常机制来提高程序的健壮性,MISRA C++给出了一些规范,但具体还需要程序员反复斟酌,甚至需要多次实验。至此,关于MISRA-C++:2008的学习暂告一段落。
在这4期的讲座中,我们主要讨论了C++对于C新增的特性,列举和解释了其中有代表性的规则,且尽量使每篇文章都能涵盖C++的一个重要特性。有些例子是在我们理解的基础上加的,可能存在着错误或偏差,欢迎大家和我们共同讨论。通过这4期介绍,希望大家能够意识到:C++对于C并不是简单的语言的改进,C++面向对象的思想从根本上影响了软件的架构。
可以预见,随着嵌入式产业的飞速发展,在嵌入式领域C++将会有辉煌的前景。对C++进行改造,使其适用于嵌入式环境,提高其可靠性,对于推动C++在嵌入式领域的应用是很重要的。MISRA-C已经在嵌入式C语言上取得了很大的成功,成为行业普遍认同和遵循的规范。我们希望MISRA-C++也能和MISRA-C一样,推动C++在嵌入式领域的规范化。
评论