c++异常处理

异常处理

  • 语法错误:变量命名,分号…
  • 逻辑错误:内存溢出,下标越界
  • 运行错误:定义如下

image-20220526160011539

  • 传统异常处理的方式:使用很多的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中的语句
      • 没有匹配到,就会执行系统的异常处理机制:一般是程序终止运行

异常处理思想

将底层发生的异常问题,逐级上报给更高级,一直到这个异常能被处理掉

image-20220526161021739

image-20220526161036553

异常处理的作用

改善程序的可读性和可维护性,将异常处理代码与主程序代码分离,适合团队开发大型项目。

有力的异常检测和可能的异常恢复,以统一方式处理异常。

在异常引起系统错误之前处理异常。

处理由库函数引起的异常。

在出现无法处理的异常时执行清理工作,并以适当的方式退出程序。

在动态调用链中有序地传播异常处理。

抛出异常

image-20220526161419442

image-20220526161428770

捕获异常

catch根据自己要捕获的异常的类型来进行捕获异常,一旦匹配就会捕捉异常

注意:

catch在进行异常匹配的时候不会进行数据类型的默认转换,只有完全一致的数据类型才会被捕获

image-20220526161647591

异常与函数

异常处理可以放在一个局部函数里,每次调用这个函数的时候,就会执行这个函数里面的异常处理机制

每次调用该函数的时候就会对异常进行重置

#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;
}

image-20220526163127137

异常和类

由于构造函数没有返回值,那么如果构造函数出错了该咋整?

传统方法是:

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; }
}

image-20220526164920654

异常对象

就是异常类构建的对象

#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;}
}

标准异常及其头文件

主要要去看文档

image-20220526165751920

image-20220526165814921

image-20220526165830257

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值