C++异常处理
C++内置了异常处理语法元素 try ,catch,throw。
try里面语句里产生异常( devide(1,0)产生除零异常),try里面函数devide用throw扔出异常值(对象,值),然后程序返回调用点,catch在调用点捕获到异常。
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。try { double r = divide(1, 0); //运行包含异常的代码 } catch(...) { cout << "error" << endl; //上面语句有异常则调用这里的语句 }
throw抛出的异常必须被catch处理。当前函数能够处理异常,则程序往下执行。当前函数无法处理异常,函数停止执行并异常返回(没有返回值)。
没有被处理的异常顺着函数调用栈向上传播,直至异常被处理,如果没有处理异常则整个程序停止。
例:
在函数3中发生异常,用关键字throw抛出异常给try,try再传递异常给catch。如果没有try和catch这样异常处理语句,throw则返回异常值1给上一个函数2,
函数2,1也做同样的工作,如果找不到异常处理语句,程序停止在函数1。
除零异常:
#include <iostream> #include <string> using namespace std; double divide(double a, double b) { if( b == 0) { throw 0; } else { return a / b; } } int main(int argc, char *argv[]) { try { divide(1, 0); } catch(...) { cout << "error" << endl; } return 0; }
规则:
一个try语句块可以跟上多个catch语句。
catch语句可以定义具体处理的异常类型。
不同类型是我异常由不同的catch语句负责。
try语句可以抛出任何类型的异常。
catch(...)用于处理任意类型的异常。
任何异常都只能被捕获(catch)一次 。
异常处理的匹配规则:
异常由throw抛出异常值后,由try传给catch,再由每个catch严格匹配异常值类型(不会进行类型转化),如果不匹配则调用下一个catch,如果程序没有匹配的catch则停止运行。
#include <iostream> #include <string> using namespace std; void Demo1() { try { throw 'c'; } catch(char c) { cout << "catch(char c)" << endl; // 不进行类型转化,一个异常只能被一个catch所捕获 } catch(short c) { cout << "catch(short c)" << endl; // 不进行类型转化 } catch(double c) { cout << "catch(double c)" << endl; // 不进行类型转化 } catch(...) { cout << "catch(...)" << endl; // 用于接收任意类型的异常,只能放在所有catch最后一个的位置 } } int main(int argc, char *argv[]) { Demo1(); // catch(...) return 0; }
catch相当于函数的调用,参数严格匹配的那种
catch语句也可以抛出异常:
try // 外层异常处理语句 { try // 内层异常处理语句 { throw 1; } catch(int i) // 内层catch中捕获异常值为int类型后处理异常或抛出异常 { throw i; } catch(...) // 内层catch捕获任意异常后处理或则抛出 { throw; } } catch(int i) //外层catch中捕获异常后处理内层异常或再抛出异常 { }
catch抛出异常的意义:统一异常类型。
当用私有库封装第三方库时,第三方库的函数func()的异常类型为short,对应的封装函数为my_func()的异常类行为int,可以在func()中抛出short类型的异常值,在函数my_func()中用catch接住异常并重新抛出int类型的异常值,这样就可以统一异常值类型了。
示例如下:
#include <iostream> #include <string> using namespace std; void lib_func(int i) // 三方库函数 { try { throw i; } catch(int i) { if(i < 0) throw -1; // 不做处理,直接抛出异常 if(i > 0) throw 1; if(i == 0) throw 0; } } void my_func(int i) // 自己库函数 { try { lib_func(i); } catch(int i) { switch(i) // 对于异常的重新解释 { case 1: throw "Timeout Exception"; break; case 0: throw "Runtime Exception"; break; case -1: throw "Invalid Parameter"; break; } } } int main(int argc, char *argv[]) { try { my_func(0); } catch(const char* cs) { cout << "Exception Info: " << cs << endl; } return 0; }
类类型的异常值:
自上而下严格匹配,子类的异常对象可以被父类catch语句块所抓住(子类初始化父类)(赋值兼容性原则)。匹配子类异常的catch放在下面,匹配父类异常的catch放在上面。
用自定义类类型来描述异常,实现如下:
#include <iostream> #include <string> using namespace std; class Base { }; class Exception : public Base //自定义异常类 { public: int m_id; string m_desc; Exception(int id, string desc) { m_id = id; m_desc = desc; } }; void lib_func(int i) // 三方库函数 { try { throw i; } catch(int i) { if(i < 0) throw -1; if(i > 0) throw 1; if(i == 0) throw 0; } } void my_func(int i) // 自己的库函数 { try { lib_func(i); } catch(int i) { switch(i) // 对于三方库异常的重新解释 { case 1: throw Exception(0,"Timeout Exception"); break; case 0: throw Exception(1,"Runtime Exception"); break; case -1: throw Exception(-1,"Invalid Parameter"); break; } } } int main(int argc, char *argv[]) { try { my_func(0); } catch(const Exception& e) // 打印异常类的信息。使用引用,防止调用拷贝构造函数 { cout << "Exception Info: " << " ID: " << e.m_id << " Description: " << e.m_desc << endl; } catch(const Base& e) // 子类可以初始化父类,这里也可以调用 { cout << "catch(const Base& e)" << endl; } return 0; }
C++标准库含有异常类族
exception类,logic_error类,runtime_error类
logic_error:可以避免的错误(空指针,下标越界)
runtimer_error:无法避免的错误(内存溢出)
