c++异常
1.异常
1)异常是指程序在运行时的反常行为,这些行为超出了所编写函数正常功能的范围
2)典型的范围包括失去数据库连接以及遇到意外输入
2.异常处理
1)c++ 异常处理涉及到三个关键字:try、catch、throw
2)throw 语句的语法如下:
throw 表达式;
throw语句用于拋出一个异常,异常是一个表达式,其值的类型可以是基本类型,也可以是类。
3)try...catch 语句的语法如下:
try { 语句组 } catch (异常类型) { 异常处理代码 } ... catch (异常类型) { 异常处理代码 } catch (...) {//能够捕获任何异常的 catch 语句 异常处理代码 }
catch 可以有多个,但至少要有一个
4)实例
#include <iostream> using namespace std; int main() { double m, n; cin >> m >> n; try { cout << "before dividing." << endl; if (n == 0) throw - 1; //抛出整型异常 else if (m == 0) throw - 1.0; //拋出 double 型异常 else cout << m / n << endl; cout << "after dividing." << endl; } catch (double d) { cout << "catch (double)" << d << endl; } catch (...) //能够捕获任何异常的 catch 语句 { cout << "catch (...)" << endl; } cout << "finished" << endl; return 0; }
运行结果:
3.析构函数与异常
1)C++标准指明析构函数不能、也不应该抛出异常:如果对象在运行期间出现了异常,C++异常处理模块有责任清除那些由于出现异常所导致的已经失效了的对象,释放它们原来所分配的资源, 这就是调用这些对象的析构函数来完成释放资源的任务,所以从这个意义上说,析构函数就是异常处理的一部分;试想,如果析构函数中都抛出异常,那异常处理模块有责任释放对象的资源,调用对象的析构函数,可现在析构过程又会出现异常,这就陷入了矛盾之中
2)当无法保证在析构函数中不发生异常时,那么就必须要把这种可能发生的异常完全封装在析构函数内部,决不能让它抛出函数之外:
class A { public: ~A() { try { do_something(); } catch (...) //能够保证任何异常的catch语句 //保证了抛出的异常不会被扔出析构函数之外 { } cout << "A被析构" << endl; } };
4.构造函数与异常
1)构造函数可以抛出异常
2)构造函数的初始化列表里抛异常将直接导致程序运行结束,不会调用析构函数,前面已经构造好的成员由编译器负责回收
class B { public: B() { cout << "construct B default" << endl; throw 3; //故意在默认构造函数中抛出异常 } B(int num) { age = num; cout << "constructor B ,age =" << num << endl; } ~B() { cout << "destructor B ,age=" << age << endl; } private: int age; }; class A { public: A() :_data(new char[1]), b(B(10)), bp(new B()) { cout << "construct A " << endl; *_data = '\0'; } ~A() { cout << "destructor A" << endl; delete[] _data; delete bp; } private: char *_data; B b; B *bp; }; int main() { A a; return 0; }
运行结果:
由结果可知:在第20行class A构造函数的初始化列表,调用B(10)正常,而调用B()则发生异常,此时A和B都构造失败了,但是它们的析构函数都没有被调用,这些资源都是编译器负责回收了
3)数组或容器中的元素构造发生异常将直接导致程序运行结束,不会调用析构函数,前面构造成功的对象由编译器负责回收
1 class C { 2 public: 3 C() 4 { 5 //得到指定范围[m,n]的随机数:r = rand()%(n - m + 1) + m; 6 num = rand() % (8 - 0) + 0; 7 cout << "constuctor C ,num = " << num << endl; 8 if (!(num % 4)) 9 { 10 throw num; 11 } 12 13 } 14 ~C() 15 { 16 cout << "destructor C, num = " << num << endl; 17 } 18 private: 19 int num; 20 }; 21 22 int main() 23 { 24 C arr[10]; 25 26 return 0; 27 }
运行结果:
由结果可知:代码第8行,num整除4时抛出异常,num=4时满足条件,然后却没有调用析构函数回收前面成功构造的数组元素,而是由编译器回收
4)多继承中某个基类的构造函数抛异常将直接导致程序运行结束,不会调用析构函数,已经构造成功的基类对象由编译器回收
1 class B { 2 public: 3 B() 4 { 5 age = 0; 6 cout << "construct B default" << endl; 7 throw 0;//抛出异常 8 } 9 10 ~B() 11 { 12 cout << "destructor B ,age=" << age << endl; 13 } 14 private: 15 int age; 16 }; 17 18 class C { 19 public: 20 C() 21 { 22 //得到指定范围[m,n]的随机数:r = rand()%(n - m + 1) + m; 23 num = rand() % (8 - 0) + 0; 24 cout << "constuctor C ,num = " << num << endl; 25 26 } 27 ~C() 28 { 29 cout << "destructor C, num = " << num << endl; 30 } 31 private: 32 int num; 33 }; 34 35 class D :public C, public B { //基类类C对象在基类B对象之前构造 36 public: 37 D() { 38 cout << "constructor D " << endl; 39 } 40 41 ~D() { 42 cout << "destrcutor D" << endl; 43 } 44 }; 45 46 int main() 47 { 48 D d; 49 50 return 0; 51 }
运行结果:
由结果可知:d的基类C部分已经构造完成,构造基类B部分时发生异常,但并没有调用析构函数,而是由编译器回收
参考资料:
https://www.cnblogs.com/geeker/p/4385445.html
http://www.cnblogs.com/fly1988happy/archive/2012/04/11/2442765.html
posted on 2019-03-02 17:17 JoeChenzzz 阅读(163) 评论(0) 编辑 收藏 举报