一、什么是异常
能预见但无法避免的错误。
二、如何抛出异常
throw 数据:
a、可以抛出基本类型的异常
throw -1;
throw "我是异常"
b、可以抛出类类型的异常
throw Student stu;
注意:不要抛出局部对象的指针的异常
注意:如果抛出了异常程序没有捕获,程序会死亡
三、如何捕获异常
try{
//可能会产生错误的代码
}
catch(数据类型1)
{
//异常处理代码1
}
catch(数据类型2)
{
//异常处理代码2
}
a、在捕获异常时不光能获得异常,还能获得抛出的数据
throw "我是异常";
catch (const char* str);
b、异常的捕获是自上而下的,不是选择最优,子类的异常捕获最好放在父类前面
A a;
throw a;
catch(A);
c、捕获异常时尽量使用引用的方式,在抛出异常时如果使用对象的方式来捕获就会调用拷贝构造,这样就会在拷贝对象的过程中再次引用引发异常的代码
四、类类型的异常
a、可以为每一种异常定义一个什么都不用做的类,他只是为了区分各种异常
b、在抛出异常的时候可能会调用异常的构造、拷贝构造、赋值构造等,如果在类中有看不到的资源,一定要把这三个函数实现
c、为了防止有自定义的异常无法被捕获,因此在定义异常类时,最后都继承标准库的异常类,这样哪怕不能精准捕获异常,也能不遗漏异常
#include <stdexcept>
五、关于异常
1、编译器会生成一段用来申请"安全区"的代码并保护他,在异常发生后,此时程序的节奏已经被打断了,除了安全区,没有任何位置是安全的,安全区能保证存储在此位置的异常对象不受破坏
2、在构造函数中发生了异常后,会直接跳转到异常处理代码,异常的构造就此中断,对此昂的构造就不完整了,不完整的对象就永远不可能调用析构函数,哪怕用dekete显式调用
3、在构造函数中的异常也可以抛,但是不要抛出构造函数,一般使用回滚机制