第十章 异常处理
异常处理机制是用于管理程序运行期间出现的非正常情况的一种结构化方法本章主要内容
1,异常的概念
2,异常的捕获与处理
15:26:27
§ 1 异常的概念
异常指程序运行期间出现的不正常的情况,与程序的错误是相关的概念
程序的错误
编译错误:语法错误
运行结果错误:语义错误
异常错误 ( bug)
大多数情况下,程序能够正常运行且能得出正确结果,只在极少数极端情况下,程序无法正常运行或运行结果不正确
15:26:27
传统的处理方法:就地处理
在程序中可能引起问题的地方进行判断,如果条件成立就马上处理例,int *pInt=new int[10000];
if(pInt==NULL)
{
cout <<,Cannot allocate memory” << endl;
exit(0);
}
else{ 正常功能语句; }
存在的问题:
1.类或函数创建者无法确定客户程序员想如何处理该异常
2.客户程序员知道如何处理该异常,却没有机会处理
3.错误处理代码掺杂于功能实现代码中,降低了可读性
一般模式为,if(条件 ){处理语句 }
15:26:27
§ 2 异常的捕获与处理
C++的异常处理通过 throw,try 和 catch 3个关键字实现
一般处理模式为函数或类的创建者在 被调用函数中检测到异常条件成立,
用 throw抛出一个异常; 在客户程序员写的 上层主调函数中使用 try检测该函数调用是否引发异常,被检测到的各种异常由 catch捕获并作相应处理
15:26:27
throw语句的一般形式为
throw 表达式 ;
其中 表达式 表示一个异常的值,可以是任意类型的对象
异常检测与捕获处理的一般形式为
try{
//语句块
}
catch(参数声明 1)
{//异常处理 1
}
catch(参数声明 2)
{//异常处理 2
}
…
catch(参数声明 n)
{
//异常处理 n
}
catch(… )
{
//异常处理 n+1
}
参数声明的形式为:
类型 参数 或 类型 & 参数
15:26:27
说明:
一个 try语句可以与多个 catch语句配套使用
若抛出异常的类型与 catch后括号中说明的数据类型相匹配,则执行该 catch语句
若异常被捕获,则 catch后括号中的参数将接收抛出异常时传递过来的值
异常的匹配与 catch语句的顺序有关,只要找到一个匹配异常类型的 catch,则其它的 catch语句都被忽略
若 catch语句不带参数,则括号内用省略号,…,表示该
catch语句捕获所有类型的异常
有多个 catch语句时,带有省略号的 catch语句应放在最后
一旦 try检测到异常且与某个 catch语句匹配,则 try块中引发异常的语句后面的语句不再执行
一个 catch语句块执行后,跳到所有 catch块之后执行
15:26:27
例:处理除数为 0的简单异常
double Div(double,double);
void main(){
double result;
try{
result=Div(1,2); cout<<"1/2 = "<<result<<endl;
result=Div(5,0); cout<<"5/0 = "<<result<<endl;
result=Div(10,3);cout<<"10/3 = "<<result<<endl;
}
catch (double e){
cout << "Divided by zero" << endl;
cout << "main function is over." << endl;
}
}
double Div(double a,double b){
if (b==0) throw 0.0;
return a/b;
}
15:26:27
例:不同类型的异常测试
int test(char *p,double e,int a){
int f = 1;
try{
if(*p>='0' && *p<='9') throw * p;
if(e<0 || e>20000)throw e;
if(a<18 || a>70)throw a;
}
catch(char s)
{f=0;cout << "password error," << s << endl;}
catch(double e)
{f = 0;cout << "earnings error," << e << endl;}
catch(int a)
{f = 0;cout << "age error," << a << endl;}
return f;
}
15:26:27
例:不同类型的异常测试(续)
void main(){
char password[8];
double earnings;
int age;
cout << "input password,earnings,age," << endl;
cin >> password >> earnings >> age;
if(test(password,earnings,age))
cout << password << " " << earnings << ",
<< age << endl;
}
15:26:27
带有异常说明的函数原型
若一个函数抛出异常,调用该函数时必须了解该函数抛出异常的类型,以便在主调函数中加以处理
在声明函数时可以在函数原型上显式指定该函数能够抛出的异常类型
1.抛出指定类型的异常
T funName(parameterList) throw(T1,T2,…,Tn);
2.不抛出异常
T funName(parameterList) throw( );
3.抛出任意类型的异常
T funName(parameterList);
15:26:27
例:指定异常的函数
void fun(int,double);
void test(int,double) throw(int,double);
const int intMax = 100000;
const double floatMax = 1E12;
void main(){
fun(102003,3.1415926);
fun(5000,1.2e38);
}
void fun(int k,double x){
try{
test(k,x);
}catch(int)
{cout << "Integer data is too large." << endl;}
catch(double)
{cout << "Float data is too large." << endl;}
}
void test(int i,double a)
{
if(i>intMax) throw i;
if(a>floatMax)throw a;
}
15:26:27
异常的再次抛出
若 catch块捕获到异常后,无法完全处理该异常,需要把该异常传递给上一层的主调函数
可在 catch块中用 throw再次抛出该异常
void trigger(){
try{ throw "Warning";}
catch(char *msg){
cout<<"trigger:Catch_"<<msg<<"_to main"<<endl;
throw;
}
}
void main(){
try{ trigger();}
catch(char * msg)
{cout<<"main:_"<<msg<<"_from trigger"<<endl;}
}
15:26:27
template <typename T>
class Array{
public:
Array(int s);
virtual ~ Array(){};
protected:
int size;
T * element;
};
template <typename T>
Array<T>::Array(int s){
if(s<1)throw s;
else{
size = s;
element = new T[size];
if(element==NULL)
throw (T*)NULL;
}
}
void main(){
int size;
cin >> size;
try{Array <int> IntAry(size);}
catch(int s)
{cout << "size if illegal" << endl;}
catch(int *)
{cout << "Cannot allocate memory" << endl;}
}
构造函数中进行异常处理
类的构造函数没有返回值,所以主调函数无法得知创建对象是否成功
C++的异常机制很适合用来解决创建对象失败的问题
15:26:27
异常处理机制是用于管理程序运行期间出现的非正常情况的一种结构化方法本章主要内容
1,异常的概念
2,异常的捕获与处理
15:26:27
§ 1 异常的概念
异常指程序运行期间出现的不正常的情况,与程序的错误是相关的概念
程序的错误
编译错误:语法错误
运行结果错误:语义错误
异常错误 ( bug)
大多数情况下,程序能够正常运行且能得出正确结果,只在极少数极端情况下,程序无法正常运行或运行结果不正确
15:26:27
传统的处理方法:就地处理
在程序中可能引起问题的地方进行判断,如果条件成立就马上处理例,int *pInt=new int[10000];
if(pInt==NULL)
{
cout <<,Cannot allocate memory” << endl;
exit(0);
}
else{ 正常功能语句; }
存在的问题:
1.类或函数创建者无法确定客户程序员想如何处理该异常
2.客户程序员知道如何处理该异常,却没有机会处理
3.错误处理代码掺杂于功能实现代码中,降低了可读性
一般模式为,if(条件 ){处理语句 }
15:26:27
§ 2 异常的捕获与处理
C++的异常处理通过 throw,try 和 catch 3个关键字实现
一般处理模式为函数或类的创建者在 被调用函数中检测到异常条件成立,
用 throw抛出一个异常; 在客户程序员写的 上层主调函数中使用 try检测该函数调用是否引发异常,被检测到的各种异常由 catch捕获并作相应处理
15:26:27
throw语句的一般形式为
throw 表达式 ;
其中 表达式 表示一个异常的值,可以是任意类型的对象
异常检测与捕获处理的一般形式为
try{
//语句块
}
catch(参数声明 1)
{//异常处理 1
}
catch(参数声明 2)
{//异常处理 2
}
…
catch(参数声明 n)
{
//异常处理 n
}
catch(… )
{
//异常处理 n+1
}
参数声明的形式为:
类型 参数 或 类型 & 参数
15:26:27
说明:
一个 try语句可以与多个 catch语句配套使用
若抛出异常的类型与 catch后括号中说明的数据类型相匹配,则执行该 catch语句
若异常被捕获,则 catch后括号中的参数将接收抛出异常时传递过来的值
异常的匹配与 catch语句的顺序有关,只要找到一个匹配异常类型的 catch,则其它的 catch语句都被忽略
若 catch语句不带参数,则括号内用省略号,…,表示该
catch语句捕获所有类型的异常
有多个 catch语句时,带有省略号的 catch语句应放在最后
一旦 try检测到异常且与某个 catch语句匹配,则 try块中引发异常的语句后面的语句不再执行
一个 catch语句块执行后,跳到所有 catch块之后执行
15:26:27
例:处理除数为 0的简单异常
double Div(double,double);
void main(){
double result;
try{
result=Div(1,2); cout<<"1/2 = "<<result<<endl;
result=Div(5,0); cout<<"5/0 = "<<result<<endl;
result=Div(10,3);cout<<"10/3 = "<<result<<endl;
}
catch (double e){
cout << "Divided by zero" << endl;
cout << "main function is over." << endl;
}
}
double Div(double a,double b){
if (b==0) throw 0.0;
return a/b;
}
15:26:27
例:不同类型的异常测试
int test(char *p,double e,int a){
int f = 1;
try{
if(*p>='0' && *p<='9') throw * p;
if(e<0 || e>20000)throw e;
if(a<18 || a>70)throw a;
}
catch(char s)
{f=0;cout << "password error," << s << endl;}
catch(double e)
{f = 0;cout << "earnings error," << e << endl;}
catch(int a)
{f = 0;cout << "age error," << a << endl;}
return f;
}
15:26:27
例:不同类型的异常测试(续)
void main(){
char password[8];
double earnings;
int age;
cout << "input password,earnings,age," << endl;
cin >> password >> earnings >> age;
if(test(password,earnings,age))
cout << password << " " << earnings << ",
<< age << endl;
}
15:26:27
带有异常说明的函数原型
若一个函数抛出异常,调用该函数时必须了解该函数抛出异常的类型,以便在主调函数中加以处理
在声明函数时可以在函数原型上显式指定该函数能够抛出的异常类型
1.抛出指定类型的异常
T funName(parameterList) throw(T1,T2,…,Tn);
2.不抛出异常
T funName(parameterList) throw( );
3.抛出任意类型的异常
T funName(parameterList);
15:26:27
例:指定异常的函数
void fun(int,double);
void test(int,double) throw(int,double);
const int intMax = 100000;
const double floatMax = 1E12;
void main(){
fun(102003,3.1415926);
fun(5000,1.2e38);
}
void fun(int k,double x){
try{
test(k,x);
}catch(int)
{cout << "Integer data is too large." << endl;}
catch(double)
{cout << "Float data is too large." << endl;}
}
void test(int i,double a)
{
if(i>intMax) throw i;
if(a>floatMax)throw a;
}
15:26:27
异常的再次抛出
若 catch块捕获到异常后,无法完全处理该异常,需要把该异常传递给上一层的主调函数
可在 catch块中用 throw再次抛出该异常
void trigger(){
try{ throw "Warning";}
catch(char *msg){
cout<<"trigger:Catch_"<<msg<<"_to main"<<endl;
throw;
}
}
void main(){
try{ trigger();}
catch(char * msg)
{cout<<"main:_"<<msg<<"_from trigger"<<endl;}
}
15:26:27
template <typename T>
class Array{
public:
Array(int s);
virtual ~ Array(){};
protected:
int size;
T * element;
};
template <typename T>
Array<T>::Array(int s){
if(s<1)throw s;
else{
size = s;
element = new T[size];
if(element==NULL)
throw (T*)NULL;
}
}
void main(){
int size;
cin >> size;
try{Array <int> IntAry(size);}
catch(int s)
{cout << "size if illegal" << endl;}
catch(int *)
{cout << "Cannot allocate memory" << endl;}
}
构造函数中进行异常处理
类的构造函数没有返回值,所以主调函数无法得知创建对象是否成功
C++的异常机制很适合用来解决创建对象失败的问题
15:26:27