异常处理机制
异常处理的三个步骤:检查异常,抛出异常,处理异常
异常处理基本原理:把需要检测的程序放到try块中,把异常处理的程序放在catch块中。如果执行一个函数出现了异常,可以抛出异常信息。然后查找try块下面的catch块是否可以处理该异常。如果该函数不处理该异常,将传递给它的上一级函数(调用函数),如果它的上一级函数收到异常后也不处理,将逐层向上传递。如果传递到了第一层(如main函数)也不处理,最后只能异常中止程序的执行。
如果异常在任何一个环节被处理,处理完成后,将继续执行处理异常的catch块下面的代码
1、抛出异常
抛出异常:可以使用throw表达式抛出异常,将异常抛掷给主调函数处理,异常通常以类似于实参传递给函数的方式(由throw)抛出和(被catch)捕获,throw表达式的类型决定了所抛出异常的类型。
由于c++是根据类型来区分不同的异常的,因此在抛出异常时,throw表达式的值没有实际意义,而表达式的类型则是非常重要的。如果程序中有多处要抛出异常,应该用不同的表达式类型来相互区别。
抛出异常表达式: throw 表达式
Int a = 1; throw a; int 类型
throw 333.33; float 类型
throw ‘a’; 字符型
关于throw的说明:
(1)执行throw的时候,不会执行跟在throw后面的语句,而是将程序从throw转移到匹配的catch,该catch可以是同一函数中的catch,也可以在直接或间接调用发生异常的上级函数中。
(2)被抛出的对象是一个用throw表达式初始化的“异常对象”。异常对象由throw创建,并初始化为被抛出的表达式副本。异常对象将传递给对应的catch,并在异常处理完成后撤销。因此异常对象必须是可以复制的类型(具有复制构造函数)。
(3)如果抛出的是数组,被抛出的对象自动转换为指向该数组首元素的指针。如果抛出的是一个函数,函数被转换为指向该函数的指针。
(4)如果抛出一个指针,该指针是一个指向派生类对象的基类指针,则那个对象将被分割,只抛出基类的部分。
(5)抛出指向局部对象的指针总是错误的,因为抛出指针的时候,必须保证进入异常处理程序是指针所指向的对象依然存在。
2、捕获异常
检测捕获异常的一般形式:
当try块中的代码抛出异常,并且被某个catch块捕获后,一旦catch子句执行结束,程序流程继续执行紧随其后的最后一个catch子句后面的语句。
catch子句中的异常说明符是有一个形参的形参列表,有三种形式:
catch(类型名A) //不关心异常类型之外的信息
catch(类型名A a) //携带了异常之外的信息
catch(...) //捕获所有异常,一般放在最后一个
3、处理异常(catch块中处理,略)
异常处理执行流程
(1)程序流程到达try块,然后执行try块内的程序块。如果没有引起异常,那么跟在try块后面的catch子句都不执行,程序从最后一个catch子句后面的语句继续执行下去。
(2)抛出异常的时候,将暂停当前函数的执行,开始查找匹配的catch语句。
(3)首先检查throw是否在try内部,如果是,检查本函数内部的catch子句,如果其中之一与抛出异常对象相匹配,就处理异常;如果找不到,退出当前函数,然后继续在调用函数中查找。
(4)在调用函数中,检查与该try块相关的catch子句,如果找到匹配的catch,就处理异常;如果找不到,则退出调用函数,然后继续在调用这个函数的函数中查找,以此类推。
(5)当catch子句被找到时,执行catch子句内部的处理程序。当catch结束时,跳转到该try块的最后一个catch子句之后的语句继续执行。
4、重抛异常
在catch子句中,可以再次抛出异常,例如:
try{
throw “hello”;
}catch(const char * ){
throw;
}
其中throw不加表达式,表示再次抛出try块中检测到的异常表达式(throw “hello”)
重抛异常不能被try-catch捕获,只能传到上一级函数。