从零开始学C++之异常(二):程序错误、异常(语法、抛出、捕获、传播)、栈展开
来源:互联网 发布:linux async同步文件 编辑:程序博客网 时间:2024/05/19 12:39
一、程序错误
编译错误,即语法错误。程序就无法被生成运行代码。
运行时错误 不可预料的逻辑错误 可以预料的运行异常 例如: 动态分配空间时可能不会成功 打开文件可能会失败 除法运算时分母可能为0 整数相乘可能溢出 数组越界……
二、异常
(一)、异常语法
throw 表达式;try{ //try语句块}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 Divide(double a, double b){ if (b == 0.0) { MyException e("division by zero"); throw e; /*throw MyException("division by zero");*/ //throw 1; } else return a / b;}int main(void){ try { cout << Divide(5.0, 0.0) << endl; } catch (MyException &e) { cout << e.what() << endl; } //catch (int) //{ // cout<<"int exception ..."<<endl; //} catch (double) { cout << "double exception ..." << endl; } catch (...) { cout << "catch a exception ..." << endl; }}
程序自定义一个异常类型MyException,从输出可以看出,Divide函数内先构造一个MyException对象e,调用构造函数,因为e是局部对象需要被析构,在析构前先调用拷贝构造函数构造另一个对象,这个对象将被catch 引用,最后这个对象在catch末尾也将被析构。
假设没有构造局部对象,直接throw , 如 throw MyException(“division by zero”); 那么将不会调用拷贝构造函数,只存在一个对象,在catch的末尾被析构。
假设throw 1; 而没有对应的catch (int) ,即使存在catch (double) 也捕获不到,不会做类型转换,此时会由catch (…) 捕获到,…表示可以捕获任何异常。
(四)、异常传播
1、try块可以嵌套
2、程序按顺序寻找匹配的异常处理器,抛出的异常将被第一个类型符合的异常处理器捕获
如果内层try块后面没有找到合适的异常处理器,该异常向外传播,到外层try块后面的catch块中寻找
3、没有被捕获的异常将调用terminate函数,terminate函数默认调用abort终止程序的执行
可以使用set_terminate函数指定terminate函数在调用abort之前将调用的函数
void MyTerminate(){ cout << "MyTerminate ..." << endl;}int main(void){ set_terminate(MyTerminate); try { try { throw MyException("test exception"); } catch (int) { cout << "Inner ..." << endl; cout << "catch a int exception" << endl; } //catch (MyException& e) //{ // cout<<"Inner ..."<<endl; // cout<<e.what()<<endl; // throw e; //} } catch (int) { cout << "Outer ..." << endl; cout << "catch a int exception" << endl; } catch (MyException &e) { cout << "Outer ..." << endl; cout << e.what() << endl; }}
其中MyException类如上,程序中将内层的catch (MyException& e) 屏蔽了,所以由外层的catch (MyException& e) 捕获,假设将两个都注释掉的话,因为没有找到合适的catch, 那么terminate 函数会被调用,并且由于事先set_terminate 函数设定了abort调用之前被调用的函数MyTerminate,故先输出MyTerminate …然后程序被终止。
三、栈展开
沿着嵌套调用链接向上查找,直至为异常找到一个catch子句。这个过程称之为栈展开。
为局部对象调用析构函数
析构函数应该从不抛出异常
栈展开期间会执行析构函数,在执行析构函数的时候,已经引发的异常但还没处理,如果这个过程中析构函数又抛出新的异常,将会调用标准库的terminate函数。
异常与构造函数
构造函数中可以抛出异常。如果在构造函数函数中抛出异常,则可能该对象只是部分被构造。即使对象只是被部分构造,也要保证销毁已构造的成员。(如果成员是指针p,因为析构函数不会被调用,故不会执行一般的delete p; 很可能造成内存泄漏)
参考:
C++ primer 第四版
Effective C++ 3rd
C++编程规范
转载自http://blog.csdn.net/jnu_simba/article/details/9344267
- 从零开始学C++之异常(二):程序错误、异常(语法、抛出、捕获、传播)、栈展开
- 从零开始学C++之异常(二):程序错误、异常(语法、抛出、捕获、传播)、栈展开
- 从零开始学C++之异常(二):程序错误、异常(语法、抛出、捕获、传播)、栈展开
- 三十四、异常(一)异常抛出、异常捕获、异常传播
- 抛出异常与栈展开(stack unwinding)
- 抛出异常与栈展开(stack unwinding)
- 抛出异常与栈展开(stack unwinding)
- 抛出异常与栈展开(stack unwinding)
- java基础(十)捕获异常还是抛出异常
- 从零开始学C++之异常(三):异常与继承、异常与指针、异常规格说明
- 从零开始学C++之异常(三):异常与继承、异常与指针、异常规格说明
- 从零开始学C++之异常(三):异常与继承、异常与指针、异常规格说明
- 从零开始学C++之异常(一):C语言错误处理方法、C++异常处理方法(throw, try, catch)简介
- 从零开始学C++之异常(一):C语言错误处理方法、C++异常处理方法(throw, try, catch)简介
- 从零开始学C++之异常(一):C语言错误处理方法、C++异常处理方法(throw, try, catch)简介
- 抛出异常和捕获异常
- 异常(捕获异常)
- 从零开始学C#——基本语法(二)
- java类方法解析器
- FMDB增加修改删除功能的实现
- Unity AssetBundle爬坑手记
- Swift 学习笔记---Initialization
- ViewPager嵌套(外层Pager禁止滑动)
- 从零开始学C++之异常(二):程序错误、异常(语法、抛出、捕获、传播)、栈展开
- 微信小程序是什么?有哪些特点?
- show engine innodb status解读
- 最简单的基于Flash的流媒体示例:网页播放器
- 【HTTP】Fiddler(一) - Fiddler简介
- Eclipse下导入外部jar包的3种方式
- linux SWAP大小与内存的关系
- 智业软件校园招聘笔试_day002
- 在windows下VC中编译多线程需要如下设置