C++学习笔记(九) 异常机制
2012-07-25 14:58
253 查看
同大多数的高级语言一样,C++也有自己的异常处理机制,用于方便的处理程序运行过程中可以预料但不可避免的错误。
C++的异常抛出方法是用throw关键字,同java不一样,C++可以抛出任何类型,包括原生数据类型和自定义数据类型等,而java则允许抛出实现throwable接口的类的实例。有一点需要注意的是,C++不存在数组或函数类型的异常,如果抛出一个数组,被抛出的对象转换为指向数组首元素的指针,如果抛出一个函数,函数被转换为指向该函数的指针。
尽管C++几乎允许抛出任何类型的异常,但我们最好还是抛出exception类或是其派生类的子对象,下图展示了C++提供的异常类的继承层次:
如果我们需要自定义异常类,可以选择继承runtime_error或是logic_error或直接继承exception类。
抛出的异常会顺着调用栈往上搜索,直到找到相应的处理块。C++的处理块的定义方式和Java类似,下面简单展示下异常处理的代码:
将可能发生异常的代码包含在try块中,后面的catch块则是异常处理的代码,可以有多个catch块。当异常抛出后,它会寻找最近的可以类型匹配的catch块,然后执行异常处理代码。如果需要将异常再次抛出,可以通过空的throw;语句将异常对象(不是catch块参数中的对象)再次往上抛出。
如果该语句可能抛出异常,但在该函数内又不想处理该异常,由于发生异常会阻断后面的代码的执行,为了使资源可以安全的回收,我们可以将异常捕获后,进行资源回收后再将其抛出。请看下面的代码:
现在catch块中不再有任何的参数,而是以...表示,它表示捕获任何的异常,这一句一般用在最后,可在catch块中释放资源,然后再继续将异常往上抛。学过java的童鞋有木有觉得它的作用很像finally块?不过他没有finally块那么强大了,它只能在异常发生的时候起作用,而finally块则是无论有木有异常发生都必须执行的块。
异常有时候也会发生在构造函数的初始化列表里,那么对于这里的异常我们该如何捕获呢?所幸C++为我们提供了特殊的机制,代码如下:
看见了吗?将try卸载初始化列表中冒号的前面就可以了,这样不仅可以捕获构造函数体里的异常,也能捕获初始化列表中的异常。
下面说一下C++中的异常描述,学过java的人对这个应该很熟悉,就是在函数的参数列表后面说明该函数可能抛出说明样的异常,这对于程序的编写来说方便了太多,不过可惜的是,大部分编译器都不会对C++的异常描述做检查,只会在程序运行时出错(比较怀念java完善的异常处理机制)。还是看一下它的定义方式吧:
该函数的异常描述说明了它可能抛出runtime_error,或是logic_error异常,当我们使用该函数时就要考虑到对这二种异常的处理,如果throw后面的括号是空的,则表示该函数不会抛出任何异常,如果没有异常描述,则表示该函数可以抛出任何异常。
一个函数的异常描述可以说是这个函数的一个限制,因此,在继承的时候,如果要重写该函数,则子类函数的异常描述列表中不可以再增加新的异常。
对于赋值也是同样的道理,以下的代码是错的:
E.Moo
《C++语言程序设计》 郑莉 董渊 何江舟
C++的异常抛出方法是用throw关键字,同java不一样,C++可以抛出任何类型,包括原生数据类型和自定义数据类型等,而java则允许抛出实现throwable接口的类的实例。有一点需要注意的是,C++不存在数组或函数类型的异常,如果抛出一个数组,被抛出的对象转换为指向数组首元素的指针,如果抛出一个函数,函数被转换为指向该函数的指针。
尽管C++几乎允许抛出任何类型的异常,但我们最好还是抛出exception类或是其派生类的子对象,下图展示了C++提供的异常类的继承层次:
如果我们需要自定义异常类,可以选择继承runtime_error或是logic_error或直接继承exception类。
抛出的异常会顺着调用栈往上搜索,直到找到相应的处理块。C++的处理块的定义方式和Java类似,下面简单展示下异常处理的代码:
try{ //可能抛出异常的代码 } catch(exception &e) { //进行异常处理的代码 }
将可能发生异常的代码包含在try块中,后面的catch块则是异常处理的代码,可以有多个catch块。当异常抛出后,它会寻找最近的可以类型匹配的catch块,然后执行异常处理代码。如果需要将异常再次抛出,可以通过空的throw;语句将异常对象(不是catch块参数中的对象)再次往上抛出。
如果该语句可能抛出异常,但在该函数内又不想处理该异常,由于发生异常会阻断后面的代码的执行,为了使资源可以安全的回收,我们可以将异常捕获后,进行资源回收后再将其抛出。请看下面的代码:
try{ //可能抛出异常的代码 } catch(...) { //进行资源回收的代码 throw; }
现在catch块中不再有任何的参数,而是以...表示,它表示捕获任何的异常,这一句一般用在最后,可在catch块中释放资源,然后再继续将异常往上抛。学过java的童鞋有木有觉得它的作用很像finally块?不过他没有finally块那么强大了,它只能在异常发生的时候起作用,而finally块则是无论有木有异常发生都必须执行的块。
异常有时候也会发生在构造函数的初始化列表里,那么对于这里的异常我们该如何捕获呢?所幸C++为我们提供了特殊的机制,代码如下:
A::A(int* p) try : ptr(p) { // empty function body } catch(exception &e){ //异常处理代码 }
看见了吗?将try卸载初始化列表中冒号的前面就可以了,这样不仅可以捕获构造函数体里的异常,也能捕获初始化列表中的异常。
下面说一下C++中的异常描述,学过java的人对这个应该很熟悉,就是在函数的参数列表后面说明该函数可能抛出说明样的异常,这对于程序的编写来说方便了太多,不过可惜的是,大部分编译器都不会对C++的异常描述做检查,只会在程序运行时出错(比较怀念java完善的异常处理机制)。还是看一下它的定义方式吧:
void test() throw(runtime_error, logic_error) { //...some implementation }
该函数的异常描述说明了它可能抛出runtime_error,或是logic_error异常,当我们使用该函数时就要考虑到对这二种异常的处理,如果throw后面的括号是空的,则表示该函数不会抛出任何异常,如果没有异常描述,则表示该函数可以抛出任何异常。
一个函数的异常描述可以说是这个函数的一个限制,因此,在继承的时候,如果要重写该函数,则子类函数的异常描述列表中不可以再增加新的异常。
对于赋值也是同样的道理,以下的代码是错的:
void test() throw(runtime_error, logic_error) { //...some implementation }
void (*p)() throw(runtime_error) = test;//error
参考文献:
《C++ Primer》Stanley B.Lippman BarbaraE.Moo
《C++语言程序设计》 郑莉 董渊 何江舟
相关文章推荐
- [学习笔记]C++中的异常机制
- 【C++】【学习笔记】【017】继承机制中的构造器和析构器
- C++学习笔记(十) 内存机制与Allocator
- 【菜鸟C++学习笔记】22. 参数的传递机制
- 【转载】C++异常机制的学习
- C++学习笔记之异常
- 关于C++异常机制的笔记(SEH, try-catch)
- C++学习笔记——异常处理匹配与函数嵌套
- C++学习二:异常机制
- C++学习笔记(十五):异常
- 【菜鸟C++学习笔记】23. 对象的传递机制
- C++学习笔记:高级编程:文件和流,异常处理,动态内存,命名空间
- JAVA学习笔记_关于异常机制处理问题
- [学习笔记]Java异常机制
- Python学习笔记之错误处理(关键词:错误处理、异常机制、try、except、else、finally、raise)
- C++学习笔记--异常简介
- java学习笔记-java异常处理机制
- JAVA学习笔记25——异常机制1:Exception简介+异常处理的try_catch_finally方法
- Struts2 学习笔记——异常机制
- C++学习笔记之WINDOWS消息机制