【c++】异常处理
1. 什么是异常?
2. 异常的分类
3. 异常处理
4. 异常的重新抛出----嵌套结构
参考:《c++从入门到精通》 人民邮电出版社
经过前面几章的学习,我们已经掌握了基本的程序编写,但是这些程序还比较脆弱,发生意料之外的问题怎么办呢?
是束手无策放任应用程序崩溃呢,还是遇到意外时让程序安全退出呢,还是选择更好的解决办法?比如:针对不同的异常问题选择不同的解决方法。
1. 什么是异常?
异常(exception),就是程序在运行过程中,由于使用环境的变化以及用户的操作而产生的错误。
所有的程序都有bug,程序规模越大,bug越多。为了尽可能地减少正式发布软件中的bug,一个软件在经历了demo版本后,会经历Alpha版本(内部测试版),然后是beta版本(外部测试版),最后才发布release版本(即 正式版本)。之后还会发布补丁包和升级版本。这就说明了所有的程序都有潜在或未发现的bug。
2. 异常的分类
按异常发生的时刻,可将异常分类为两种:
(1) 语法错误:程序中执行了错误的语句或者函数类等,导致编译程序无法进行。
(2) 运行时发生的错误:这一般与算法、逻辑有关。常见的有:文件打开失败、数组下标溢出、系统内存不足等。
3. 异常处理
异常处理是对程序运行过程中突如其来的错误的处理。使用异常处理机制,可以使程序更加安全、可靠。
异常处理机制的本质是:程序处理流程的转移,适度的、恰当的转移会起到很好的作用。
(1) 异常处理语句块
异常处理语句块有3个:try\catch\throw。
Try语句块:用来框定异常。要处理异常,先框定可能产生异常的语句块。
Catch语句块:定义处理异常。将出现异常后的处理语句放在catch块中,以便当异常被抛出后,进行类型匹配,捕获异常并处理。
Throw语句块:抛出异常。在可能产生异常的语句中进行错误检查,如果有错误,就抛出异常。
(2) 使用try-throw-catch处理异常
使用try-throw-catch处理异常 ,格式为:
【异常处理实例】
代码:
//异常处理.cpp
#include<iostream>
#include<string>
using namespace std;
class myClass{} ;
struct myStruct{};
void fun(int i)
{
try{ // 可能出现异常的语句块,根据i值的不同,抛出不同的异常
if(i==1)
{
throw 1 ; //抛出整型异常
}
else if(i==2)
{
throw 1.2 ; //抛出double异常
}
else if(i==3)
{
throw myClass() ; //抛出 类 异常
}
else if(i==4)
{
throw myStruct() ; //抛出 结构体 异常
}
}
catch(int i) //捕获整型异常
{
cout<<"catch is int\n";
}
catch(double a) //捕获double异常
{
cout<<"catch is double\n";
}
catch(myClass) //捕获 类 异常
{
cout<<"catch is myClass\n";
}
catch(...) //捕获 结构体 异常
{
cout<<"catch is myStruct\n";
}
}
int main(int argc,char *argv[])
{
try
{
fun(1);
fun(2);
fun(3);
fun(4);
}
catch(int i)
{
cout<<"main() error!"<<endl;
}
cout<<"main() is OK!"<<endl;
return 0;
}
运行结果:
经分析可发现,catch会根据throw抛出的不同类型,来进行捕获。
4. 异常的重新抛出----嵌套结构
在c++异常处理的嵌套结构中,规则是:外层的throw抛出的异常使用外层的catch来捕获,内层的throw抛出的异常使用内层的catch来捕获。
如果我们希望内层抛出的异常由外层的catch来捕获,这就需要使用异常的层层传递手段了,这要用到throw语句不带表达式的形式。
throw语句(不带表达式),内嵌在catch内,意味着当前catch块在入口中捕获的类型信息,throw接力地将此类型信息抛出到上层的相应类型入口的catch捕获器,特定异常就从内层传到了外层需要的地方。
【编程实例】实现异常嵌套
代码:
//异常嵌套处理.cpp
#include<iostream>
#include<string>
using namespace std;
void funa(int i)
{
try{ // 可能出现异常的语句块,根据i值的不同,抛出不同的异常
if(i==1)
{
throw 1 ; //抛出整型异常
}
else if(i==2)
{
throw 1.2; //抛出double异常
}
}
catch(int i) //捕获整型异常
{
cout<<"funa 抛出int异常\n";
throw;
}
catch(double a) //捕获double异常
{
cout<<"funa 抛出double异常\n";
throw;
}
cout<<"funa 正常运行\n";
}
void funb(int i)
{
try
{ // 可能出现异常的语句块,根据i值的不同,抛出不同的异常
funa(i);
}
catch(int i) //捕获整型异常
{
cout<<"funb 重新抛出int异常\n";
throw;
}
catch(double a) //捕获字符串异常
{
cout<<"funb 重新抛出double异常\n";
throw;
}
}
void func(int i)
{
try
{ // 可能出现异常的语句块,根据i值的不同,抛出不同的异常
funb(i);
}
catch(int i) //捕获整型异常
{
cout<<"func 最终解决int异常\n";
}
catch(double a) //捕获字符串异常
{
cout<<"func 最终解决double异常\n";
}
}
int main(int argc,char *argv[])
{
int a=1;
int b=2;
try
{
func(a);
func(b);
}
catch(int i)
{
cout<<"main() error!"<<endl;
}
cout<<"main() is OK!"<<endl;
return 0;
}
运行结果:
经分析,可发现,调用func时,需调用funb,调用funb需调用funa。这样就构成了嵌套结构,同时利用catch和throw也实现了不同层级的异常的传递和处理。
------------------------------------------- END -------------------------------------