异常处理
- 语法错误:变量命名,分号…
- 逻辑错误:内存溢出,下标越界
- 运行错误:定义如下
- 传统异常处理的方式:使用很多的if分支语句进行处理
执行任务1
if 任务1未能被正确执行
执行错误处理程序
执行任务2
if 任务2未能正确执行
执行错误处理程序
执行任务3
- 新的异常处理方式是:检测异常,抛出异常,最后捕获异常并进行处理
try-throw-catch的基本结构
try{
…… //try程序块
if err1 throw xx1
……
if err2 throw xx2
……
if errn throw xxn
}
catch(type1 arg){……} //异常类型1错误处理
catch(type2 arg){……} //异常类型2错误处理
catch(typem arg){……} //异常类型m错误处理
try-throw-catch异常处理方式
- 执行到try语句中,就进行try语块中的程序语句,这些语句是可能出现异常的语句
- 没有异常就会全部执行完毕,并且忽略掉紧挨着这个try语块的catch语句(也就是没有捕获到异常)
- 如果出现异常就会执行出现异常部分的throw,将异常抛出,try语块中的其他语句将不再执行,然后就会throw出的异常和后面的catch中的异常类型进行匹配
- 如果匹配到了,就会执行相对应catch中的语句
- 没有匹配到,就会执行系统的异常处理机制:一般是程序终止运行
异常处理思想
将底层发生的异常问题,逐级上报给更高级,一直到这个异常能被处理掉
异常处理的作用
改善程序的可读性和可维护性,将异常处理代码与主程序代码分离,适合团队开发大型项目。
有力的异常检测和可能的异常恢复,以统一方式处理异常。
在异常引起系统错误之前处理异常。
处理由库函数引起的异常。
在出现无法处理的异常时执行清理工作,并以适当的方式退出程序。
在动态调用链中有序地传播异常处理。
抛出异常
捕获异常
catch根据自己要捕获的异常的类型来进行捕获异常,一旦匹配就会捕捉异常
注意:
catch在进行异常匹配的时候不会进行数据类型的默认转换,只有完全一致的数据类型才会被捕获
异常与函数
异常处理可以放在一个局部函数里,每次调用这个函数的时候,就会执行这个函数里面的异常处理机制
每次调用该函数的时候就会对异常进行重置
#include<iostream>
using namespace std;
void temperature(int t)
{
try{
if(t==100) throw "沸点!";
else if(t==0) throw "冰点!";
else cout<<"the temperature is OK..."<<endl;
}
catch(int x){cout<<"temperatore="<<x<<endl;}
catch(char *s){cout<<s<<endl;}
}
void main()
{
temperature(0); //L1
temperature(10); //L2
temperature(100); //L3
}
/*程序运行结果:
冰点!
The temperature is OK…
沸点!
*/
我们也可以将异常的检测和抛出的代码放在一个函数里面,然后把异常捕获的代码放在另外一个函数中,这样的异常处理会更加灵活实用
#include<iostream>
using namespace std;
void temperature(int t)
{
if(t==100) throw "沸点!";
else if(t==0) throw "冰点!";
else cout<<"the temperature is ..."<<t<<endl;
}
void main()
{
try{
temperature(10);
temperature(50);
temperature(100);
}
catch(char *s){cout<<s<<endl;}
}
异常处理的几种特殊情况
1.单个catch可以捕获各种异常
形式:
catch(…) {
…… //异常处理代码
}
catch(想捕获的异常的数据类型列表)
列表中的异常都会被这个catch所捕获
2.再次抛出异常
当一个catch块无法处理该异常的时候,可以将该异常抛出,给别的catch块处理,比如说向外层传递,从底层向上一层传递
为了达成这个操作,只需要在这个catch块的结尾,加上不跑出任何异常的throw语句就ok
#include<iostream>
using namespace std;
void Errhandler(int n)throw()
{
try{
if(n==1) throw n;
cout<<"all is ok..."<<endl;
}
catch(int n){
cout<<"catch an int exception inside..."<<n<<endl;
throw; //再次抛出本catch捕获的异常
}
}
void main(){
try{Errhandler(1); }
catch(int x){ cout<<"catch an int exception in main..."<<x<<endl; }
cout<<"....End..."<<endl;
}
/*
catch an int exception inside...1
terminate called after throwing an instance of 'int'
*/
异常的嵌套调用
try块可以嵌套,即一个try块中可以包括另一个try块,这种嵌套可能形成一个异常处理的调用链.
#include<iostream>
using namespace std;
void fc(){
try{throw "help...";}
catch(int x){cout<<"in fc..int hanlder"<<endl;}
try{cout<<"no error handle..."<<endl;}
catch(char *px){cout<<"in fc..char* hanlder"<<endl;}
}
void fb(){
int *q=new int[10];
try{
fc();
cout<<"return form fc()"<<endl;
}
catch(…){
delete []q;
throw;
}
}
void fa()
{
char *p=new char[10];
try{
fb();
cout<<"return from fb()"<<endl;
}
catch(…){
delete []p;
throw;
}
}
int main(){
try{
fa();
cout<<"return from fa"<<endl;
}
catch(…){cout<<"in main"<<endl;}
cout<<"End"<<endl;
return 0;
}
异常和类
由于构造函数没有返回值,那么如果构造函数出错了该咋整?
传统方法是:
1.返回一个处于错误状态的对象,外部程序可以检查该对象状态,以便判定该对象是否被成功构造。
2.设置一个全局变量保存对象构造的状态,外部程序可以通过该变量值判断对象构造的情况。
3.在构造函数中不做对象的初始化工作,而是专门设计一个成员函数负责对象的初始化。
而异常处理机制是,在构造出错的时候就抛出异常,外部函数可以在外部捕获异常进行处理
异常类
异常可以是任何类型,包括自定义类,用来传递异常信息的类就是异常类
异常类可以很简单,甚至没有数据成员
他也可以像普通类一样有构造函数,成员函数,数据成员,虚函数等等
甚至可以派生产生继承层次结构
#include <iostream>
using namespace std;
const int MAX=3;
class Full{}; //L1 堆栈满时抛出的异常类
class Empty{}; //L2 堆栈空时抛出的异常类
class Stack{
private:
int s[MAX];
int top;
public:
void push(int a);
int pop();
Stack(){top=-1;}
};
void Stack::push(int a){
if(top>=MAX-1) throw Full();
s[++top]=a;
}
int Stack::pop(){
if(top<0) throw Empty();
return s[top--];
}
void main(){
Stack s;
try{
s.push(10); s.push(20); s.push(30);
//s.push(40); //L5 将产生栈满异常
cout<<"stack(0)= "<<s.pop()<<endl;
cout<<"stack(1)= "<<s.pop()<<endl;
cout<<"stack(2)= "<<s.pop()<<endl;
cout<<"stack(3)= "<<s.pop()<<endl; //L6
}
catch(Full){ cout<<"Exception: Stack Full"<<endl; }
catch(Empty){ cout<<"Exception: Stack Empty"<<endl; }
}
异常对象
就是异常类构建的对象
#include <iostream>
using namespace std;
const int MAX=3;
class Full{
int a;
public:
Full(int i):a(i){}
int getValue(){return a;}
};
class Empty{};
class Stack{
private:
int s[MAX];
int top;
public:
Stack(){top=-1;}
void push(int a){
if(top>=MAX-1)
throw Full(a);
s[++top]=a;
}
int pop(){
if(top<0)
throw Empty();//出现异常,抛出Empty对象
return s[top--];
}
};
void main(){
Stack s;
try{
s.push(10);
s.push(20);
s.push(30);
s.push(40);
}
catch(Full e){ //捕获Empty类型的异常对象
cout<<"Exception: Stack
Full..."<<endl;
cout<<"The value not push in stack: “
<<e.getValue()<<endl;
}
}
派生异常类的处理
#include<iostream>
using namespace std;
class BasicException{
public:
char* Where(){return "BasicException...";}
};
class FileSysException:public BasicException{
public:
char *Where(){return "FileSysException...";}
};
class FileNotFound:public FileSysException{
public:
char *Where(){return "FileNotFound...";}
};
class DiskNotFound:public FileSysException{
public:
char *Where(){return "DiskNotFound...";}
};
void main(){
try{
..... //程序代码
throw FileSysException();
}
catch(DiskNotFound p){cout<<p.Where()<<endl;}
catch(FileNotFound p){cout<<p.Where()<<endl;}
catch(FileSysException p){cout<<p.Where()<<endl;}
catch(BasicException p){cout<<p.Where()<<endl;}
try{
..... //程序代码
throw DiskNotFound();
}
catch(BasicException p){cout<<p.Where()<<endl;}
catch(FileSysException p){cout<<p.Where()<<endl;}
catch(DiskNotFound p){cout<<p.Where()<<endl;}
catch(FileNotFound p){cout<<p.Where()<<endl;}
}
异常类继承结构也可以用多态实现,多态可以简化异常的捕获。
#include <iostream>
using namespace std;
class BasicException{
public:
virtual char* Where(){return "BasicException...";}
};
class BasicException{
public:
char* Where(){return "BasicException...";}
};
class FileSysException:public BasicException{
public:
char *Where(){return "FileSysException...";}
};
class FileNotFound:public FileSysException{
public:
char *Where(){return "FileNotFound...";}
};
class DiskNotFound:public FileSysException{
public:
char *Where(){return "DiskNotFound...";}
};
void main(){
try{
//..... 程序代码
throw FileSysException();
}
catch(BasicException &p){cout<<p.Where()<<endl;}
try{
//..... 程序代码
throw DiskNotFound();
}
catch(BasicException &p){cout<<p.Where()<<endl;}
}
标准异常及其头文件
主要要去看文档