生命周期 异常在被调函数中触发,不断传向下一级主调函数,直到被捕获
ps:若异常无法被捕获,程序会调用库函数terminate,由库函数调用abort函数终止程序
关键字 1. throw throw + 表达式:抛出异常
ps:表达式可以是数据,也可以是函数(必须有返回值 )
2. try + catch ps:catch (...)表示通用捕获,任何异常均可捕获,但是无法获取异常的值,一般放在所有catch最后
注:catch (基类异常)可以捕获派生类异常,若基类异常和派生类异常同存,一般将基类异常的捕获放在后面
1 2 3 4 5 6 7 8 9 10 11 12 try { 	... } catch  (exception &e){     ... } catch  (...){     ... } 
 
实例 除零异常 分析:try块处理了三个除法(15~17行);第二个除法除数为0,divide抛出被除数8被捕获并打印异常信息
ps:try当中抛出异常后的语句无法执行,对应第三个除法(17行)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include  <iostream>  using  namespace  std;float  divide (float  x, float  y)  {	if  (0  == y) 		throw  x; 	return  x / y; } int  main ()  {	try   	{ 		cout << "5 / 2 = "  << divide (5 , 2 ) << endl; 		cout << "8 / 0 = "  << divide (8 , 0 ) << endl; 		cout << "7 / 1 = "  << divide (7 , 1 ) << endl; 	} 	catch (float  e) 	{ 		cout << e << " is divided by zero!"  << endl; 	} 	return  0 ; } 
 
异常接口声明 1 void  func ()  throw (A, B, C, D) 	
 
 
异常处理中的构造与析构 基本原理 从对应的try块开始到异常被抛出之间构造(且尚未析构)的所有自动对象进行析构
ps:若异常不被捕获则无法析构
实例 分析:主要观察demo的析构是否被执行
异常可以被捕获: 
demo在退出try块之后正常析构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include  <iostream>  using  namespace  std;class  MyException { public :	MyException (const  string &message) : message (message) {} 	const  string &getMessage ()  const   { return  message; } private :	string message; }; class  Demo { public :	Demo () { cout << "Constructor of Demo"  << endl; } 	~Demo () { cout << "Destructor of Demo"  << endl; } }; void  func ()  throw (MyException)  {	Demo demo; 	cout << "Throw MyException in func()"  << endl; 	throw  MyException ("exception thrown by func()" ); } int  main ()  {	try   	{ 		func (); 	} 	catch (MyException &e) 	{ 		cout << e.getMessage () << endl; 	} 	return  0 ; } 
 
 正常析构  
              
             
异常无法被捕获: 
库函数terminate调用abort函数终止程序,demo未被析构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include  <iostream>  using  namespace  std;class  MyException { public :	MyException (const  string &message) : message (message) {} 	const  string &getMessage ()  const   { return  message; } private :	string message; }; class  Demo { public :	Demo () { cout << "Constructor of Demo"  << endl; } 	~Demo () { cout << "Destructor of Demo"  << endl; } }; void  func ()  throw (MyException)  {	Demo demo; 	cout << "Throw MyException in func()"  << endl; 	throw  MyException ("exception thrown by func()" ); } int  main ()  {	try   	{ 		func (); 	} 	catch (int  e) 	{ 		cout << e << endl; 	} 	return  0 ; } 
 
 无法析构  
              
             
常见问题 
解决方案 
在所有catch最后加一个catch(...)捕获所有类型的异常 
 
标准程序库的异常类 头文件  
异常类汇总  点击查看  
              
             
常用异常类 
exception:标准程序库异常类的公共基类 
logic_error:表示可以在程序中被预先检测到的异常(这类异常可以避免) 
runtime_error:表示难以被预先检测到的异常 
 
实例 三角形面积计算 
判断边长是否合理(为正数且满足三角不等式),不合理抛出invalid_argument异常;合理则输出三角形面积
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include  <iostream>  #include  <cmath>  #include  <stdexcept>  using  namespace  std;double  area (double  a, double  b, double  c)  throw (invalid_argument)  {	 	if  (a <= 0  || b <= 0  || c <= 0 ) 	{ 		throw  invalid_argument ("The side length should be positive!" ); 	} 	 	if  (a + b <= c || a + c <= b || b + c <= a) 	{ 		throw  invalid_argument ("The side length should fit the triangle inequaltion!" ); 	} 	 	double  aver = (a + b + c) / 2 ; 	return  sqrt (aver * (aver - a) * (aver - b) * (aver - c)); } int  main ()  {	double  a, b, c, res; 	cout << "请输入三角形边长:" ; 	cin >> a >> b >> c; 	try  	{ 		res = area (a, b, c); 	} 	catch  (invalid_argument& e) 	{ 		cout << e.what () << endl; 		return  0 ; 	} 	cout << "三角形的面积为:"  << res << endl; 	return  0 ; } 
 
编写异常安全程序的原则 
避免异常引发的资源泄露 常见问题 
函数在抛出异常以前没有释放应该由它负责 释放的资源(例如用new分配的变量是不可以自动析构的,必须使用free) 
 
解决方案 
把一切动态分配的资源都包装成栈上的对象,利用抛掷异常时自动调用对象析构函数的特性来释放资源 
对于必须在堆上构造的对象,可以用智能指针auto_ptr加以包装