当前位置:文档之家› C++异常处理机制全解

C++异常处理机制全解

C++异常处理机制全解▌异常处理(Exception handling)●返回一个错误码进行异常处理(C语言):例:bool func(float a, float b, float& c){if(b==0){return false;}c=a/b;return true;}int main(){float a=10;float b=0;float c=0;bool result=func(a, b, c);if(!result){cout<<"The func fails!"<<endl;return 0;}else{cout<<"The func succeeds!"<<endl;}//func1();//func2();return 0;}●try-throw-catch语句(C++);例:void func(float a, float b, float& c){if(b==0){ //如果b为0,则抛出字符串“Divided by zero!”;throw "Divided by zero"; //throw出来的东西可以是任何类型,甚至可以是类的对象;}c=a/b;}int main(){float a=10;float b=0;float c=0;try{ //测试条件;func(a, b, c);//func1();//func2();}catch(const char* str){ //捕获异常信息;cout<<str<<endl;}//func4();return 0;}★try:诊断异常代码;例:try{//可能出现异常的情况}☆可能出现异常的三种情况:①可执行语句;②一个函数调用;③一个函数调用另一个函数;★throw:抛出错误信息;例:if(分母==0){throw 参数(只有一个,可以是任何类型,甚至是一个对象)}★catch:捕获异常信息;例:catch(参数类型参数){ //只能有一个参数,这里的形参可以被省略,但是省略后不能输出异常信息,依然可以捕获;cout<<参数<<endl;}☆☆☆如果throw抛出了异常,异常类型如果与catch块后面的类型匹配,catch块内的代码将会被执行,在try语句后面可以有多个catch块,程序会寻找第一个相匹配的catch块,实行catch块的语句代码,然后跳到最后一个catch块的下一行代码,如果没有匹配的catch块,则异常返回上一层try-catch语句,如果没有相应的catch发现,程序将会终结。

★catch块不能访问try块里面定义的临时变量。

★try-throw-catch的三种写法:例://1void func(){float x, num, den;... //initialize num and dentry{ //把操作放到try块里面,不良的写法;if(den==0){throw "Divided by zero";}x=num/den;}//...}//2float divide(float a, float b){ //在函数体中实现操作,推荐写法;if(b==0){throw "divided by zero";}return a/b;}void func(){float x, num, den;//initialize num and dentry{x=divide(num, den);}catch(const char* error){cout<<error;}//...}//3float divide(float a, float b){if(b==0){throw "divided by zero";}return a/b;}float middle(float a, float b){ //嵌套写法,推荐写法;return divide(a, b);}void func(){float x, num, den;//initialize num and dentry{x=middle(num, den);}catch(char* error){cout<<error;}//...}▌再次抛出一个异常:例:#include<iostream>using namespace std;float divide(int a, int b){if(b==0){throw "divided by zero";}return float(a)/float(b);}float middle(int a, int b){try{return divide(a, b);}catch(const char* str){cout<<"Caught by function middle."<<endl;throw str;}}void func(int d){float x;int num=100;int den=d;//initialize num and dentry{x=middle(num, den);}catch(const char* error){cout<<error<<endl;}}int main(){int i=1;cin>>i;func(i);return 0;}▌catch块命令:★通用格式:catch(...) //这里的三个点表示可以捕获任何异常;{//...}☆由于没有参数在上面,所以不能使用这些异常信息。

☆如果有一个catch块比另一个catch块更通用,则通用的catch块放在后面。

例:class Base;class Derived : public Base;Base b;Derived d;func(){throw "First exception"; //抛出一个字符串;throw d; //抛出一个子类对象;}try{func();}catch(const char* str){}catch(const int a){}catch(const Derived& d) //捕获子类对象;//catch(const Base& b) //可以捕获,子类对象可以当基类对象来使(公有继承);..catch(...){}☆catch块捕获一个对象时,catch块一般是子类放前面,基类放后面。

▌▲栈展开(Stack unwinding):★定义:如果一个函数里产生异常,那么这个函数将会被终结,并且本地变量(栈上的变量)会被释放。

但是如果有指针且动态分配了内存,那么栈上的指针将会被释放,而指针指向的堆内存没有被释放,这时会发生内存泄漏。

在这种情况下,为了避免内存泄漏,必须把指针抛给它的上一层调用者,让它来释放这块堆内存。

我们可以把这个指针封装到一个错误消息类里面去,然后抛出这个类的对象(构造函数构造的临时对象),为了避免临时对象的生成,我们在catch块里用这个类的引用做参数。

例:func(){int a=5; //在栈上声明的;int b=8; //在栈上声明的;char* p=new char[100] //p在栈上,p指向的内存在堆上;//throw "exception"; //会发生内存泄漏;......}▲为了避免内存泄露,我们需要将指针抛出。

我们把指针封装在一个错误类里面,然后把对象抛出,为了避免拷贝构造,我们传一个对象的引用。

例:☆☆☆#include<iostream>using namespace stdclass Error_message{public:char* message;int* arrayptr;Error_message(char* str, int* p):message(str),arrayptr(p){}};void f(){int* a=new int[10];int i=0;if(i==0){throw Error_message("error", a); //throw "error"(抛出一个构造函数构造出来的临时对象); }delete [] a; //已经throw了,这里的delete无作用;}void g(){try{f();}catch(Error_message& m){delete [] m.arrayptr; //通过构造函数删除指针在堆上分配的空间;cout<<m.message<<endl;}catch(const char* str){cout<<str<<endl;}}int main(){g();return 0;}▌不捕获异常(Uncaught exception):★定义:如果一个异常没有被catch住,或者没有写catch块,这种情况就叫不捕获异常。

如果一个异常没有被捕获住,则会终结(terminate)函数。

例:func(){int* p=new char[100000000000000];if(p==NULL){throw "exception"; //此处终结函数;}delete p;}void my_clear(){cout<<"OK,clear!"<<endl;}//terminate()set_terminate(my_clear); //调用set_terminate()捕获异常;int main(){func();}▲terminate()...(缓冲区)[set_terminate()]...-->abort()【terminate()调用abort()进行终结,我们在缓冲区(在里面调用set_terminate)来解决异常。

】☆void set_terminate( void(*)() ) //set_terminate()原型。

void(*)()是一个函数指针,这个函数叫回调函数。

例:#include<iostream>#include<exception> //包含set_terminate()的头文件;using namespace std;void my_terminate(){cout<<"Uncaught exception.\n";}float divide(int x, int y){if(y==0){throw "divide by zero";}return float(x)/float(y);}int main(){set_terminate(my_terminate);cout<<divide(1, 0);return 0;}▌异常指定:★定义:可以对抛出的异常进行指定(字符串、对象等等),throw语句不能抛出指定以外的东西。

相关主题