异常
2016-01-08 11:19
246 查看
C语言错误处理方法
返回值(if…else语句判断错误)errno
goto语句
setjmp、longjmp(这种跳转不会调用对象析构函数,因为对象不能被正常清理)
C语言的出错处理是被认为是紧耦合的,函数的使用者必须在非常靠近函数调用的地方编写错误处理代码,这会使得其变得笨拙以及难以使用
程序错误
编译错误即语法错误,程序就无法被生成运行代码。
运行时错误
不可预料的逻辑错误
可以预料的运行异常
异常语法
try { //try语句块 //throw <表达式> } catch (类型1 参数1) { //针对类型1的异常处理 } catch (类型2 参数2) { //针对类型2的异常处理 } ... catch (类型n 参数n) { //针对类型n的异常处理 }
异常抛出
可以抛出内置类型的异常,也可以抛出自定义类型异常throw抛出一个类对象会调用拷贝构造函数
异常发生之前创建的局部对象被销毁,这一过程称为栈展开
#include <iostream> #include <string> using namespace std; class MyException { public: MyException(const char* message) : message_(message) { cout << "MyException ..." << endl; } MyException(const MyException& other) : message_(other.message_) { cout << "Copy MyException ..." << endl; } ~MyException() { cout << "~MyException ..." << endl; } const char* What() const { return message_.c_str(); } private: string message_; }; double Devide(double a, double b) { if (b == 0.0) { MyException e("devision by zero ."); throw e; //调用拷贝构造函数 } else return a / b; } int main(void) { try { cout << Devide(5.0, 0.0) << endl; } catch (MyException& e) { cout << e.What() << endl; } }
异常捕获
一个异常处理器一般只捕获一种类型的异常异常处理器的参数类型和抛出异常类型的类型相同
… 表示可以捕获任何异常
异常传播
try块可以镶嵌程序按顺序寻找匹配的异常处理器,抛出的异常将被第一个类型符合的异常处理器捕获
如果内层try块后面没有找到合适的异常处理器,该异常向外传播,到外层try块后面的catch块中寻找
没有被捕获的异常将调用terminate函数,terminate函数默认调用abort终止程序的执行
可以使用set_terminate函数指定terminate函数将调用的函数
#include <iostream> #include <string> using namespace std; class MyException { public: MyException(const char* message) : message_(message) { cout << "MyException ..." << endl; } MyException(const MyException& other) : message_(other.message_) { cout << "Copy MyException ..." << endl; } ~MyException() { cout << "~MyException ..." << endl; } const char* What() const { return message_.c_str(); } private: string message_; }; double Devide(double a, double b) { if (b == 0.0) { MyException e("devision by zero ."); throw e; //调用拷贝构造函数 } else return a / b; } void MyTerminate() { cout << "MyTerminate" << endl; exit(-1); } int main(void) { set_terminate(MyTerminate); try { try { cout << Devide(5.0, 0.0) << endl; } catch (int) { cout << "Inner Catch ..." << endl; } } catch (int) { cout << "Outer Catch ..." << endl; } }
栈展开
沿着嵌套调用链接向上查找,直至为异常找到一个catch子句。这个过程称之为栈展开为局部对象调用析构函数
析构函数应该从不抛出异常
栈展开期间会执行析构函数,在执行析构函数的时候,已经引发的异常但还没处理,如果这个过程中析构函数有抛出新的异常,将会调用标准库的terminate函数
异常与构造函数
构造函数中可以抛出异常。如果在构造函数中抛出异常,则可能该对象只是部分被构造。及时对象只是被部分构造,也要保证销毁已构造的成员。
相关文章推荐
- JSR
- 【甘道夫】HBase开发环境搭建过程中可能遇到的异常:No FileSystem for scheme: hdfs
- 全球顶级专家为你解读:什么是真正的 DevOps?
- 数论 - 119. Magic Pairs
- 手机端页面需要用rem设置字体大小的js代码
- 定义数组或遍历数组并输出
- Android jar包里面有assets目录下有文件,APP的assets里面也有文件,如何读呢?
- sencha touch 学习(1)
- HTTPS那些事(一)HTTPS原理
- ShareSDK微信支付成功不调用onResp、openURL、handleOpenURL等方法
- JAVA线程锁lock下Condition高级使用-多个Condition的整合使用
- event.button在火狐和IE下的不同
- 无向图的邻接多重表结构,存储结构及基本功能实现(最全)
- 全球顶级专家为你解读:什么是真正的 DevOps?
- java基础-参数数量可变的方法
- JSP中的编码问题-解决页面乱码
- 使用GDB调试GO<一>
- android studio系列之获取数字签名
- move 设置一个widget的位置
- OC 之协议