本文参照于狄泰软件学院——《C++深度剖析课程》
之前我们分析了C语言中异常处理的方式,基本没有好的解决方案。那么C++中会如何优化C语言对异常的处理的缺陷呢?
C++中的异常处理
- C++内置了异常处理的语法元素try…catch…
- try语句处理正常代码逻辑
- catch语句处理异常情况
- try语句中的异常由对应的catch语句处理
try
{
double r = divide(1, 0);
}
catch
{
cout << "Divided by zero..." << endl;
}
疑问:这种方式跟C语言的if…else…处理方式有什么区别吗?
- C++通过throw语句抛出异常信息
- throw抛出的异常必须被catch处理
- 当前函数能够处理异常,程序继续往下执行
- 当前函数无法处理异常,则函数停止执行,并返回。
- 未被处理的异常会顺着函数调用栈向上传播,直到被处理为止,否则程序将停止执行。
示例代码:C++异常处理初探
#include <iostream>
#include <string>
using namespace std;
double divide(double a, double b)
{
const double delta = 0.000000000000001;
double ret = 0;
if( !((-delta < b) && (b < delta)) )
{
ret = a / b;
}
else
{
throw 0;
}
return ret;
}
int main(int argc, char *argv[])
{
try
{
double r = divide(1, 0);
cout << "r = " << r << endl;
}
catch(...)
{
cout << "Divided by zero..." << endl;
}
return 0;
}
分析:
1. 相对于C语言的处理方式,C++异常的处理方式更加直观了。
a) 不需要增加函数参数
b) 不需要返回异常信息
c) 不需要使用全局变量
- catch(…)用于处理所有类型的异常。
问题:C语言可以处理多个异常情况,那么C++的try…catch有这样的处理方式吗?
处理多个异常
示例代码:C++异常处理规则
#include <iostream>
#include <string>
using namespace std;
void Demo1()
{
throw 3.14;
try
{
throw 'c';
}
catch(char c)
{
cout << "catch(char c)" << endl;
}
catch(short c)
{
cout << "catch(short c)" << endl;
}
}
void Demo2()
{
throw string("D.T.Software");
}
int main(int argc, char *argv[])
{
try
{
Demo1();
}
catch(double d)
{
cout << "catch(double d)" << endl;
}
try
{
Demo2();
}
catch(char* s)
{
cout << "catch(char *s)" << endl;
}
catch(const char* cs)
{
cout << "catch(const char *cs)" << endl;
}
catch(string ss)
{
cout << "catch(string ss)" << endl;
}
catch(...)
{
cout << "catch(...)" << endl;
}
}
输出结果:
catch(double d)
catch(string ss)
分析:
1、 当函数抛出(throw)异常时,该函数结束执行,相当于C语言中的return。
2、 当抛出的异常找不到相应的catche时,未被处理的异常会顺着函数调用栈向上传播,直到被处理为止,否则程序将停止执行。
这就是Demo1() 一进入函数就抛出异常throw 3.14;马上结束了该函数的执行,返回到main函数中寻找相应的catch。如果没有相应的catch,程序就会被终止。
3、 catch 语句可以定义具体处理的异常类型
4、 不同类型的异常由不同的catch 语句负责处理,并且任何异常都只能被捕获(catch )一次
5、 try 语句中可以抛出任何类型的异常
6、 catch (…)用于处理所有类型的异常
这就是Demo2() ,抛出string类型的异常。在主函数中只会找到相应的catch(string ss)进行执行。对于后面的处理任何异常的catch(…)视而不见。
异常抛出后,至上而下严格匹配每一个catche语句处理的类型,不进行任何的类型转换。并且只会执行一次。如果找不到相应的catch。则顺着函数调用栈向上传播,知道被处理为止,否则程序将停止执行
在catch中抛异常使其与第三方库兼容
问题:如果我们在catch语句块中抛出异常。那么会怎么样?为什么需要这么做?
从上面我们的分析其实很容易知道,当throw时,就会停止执行该函数,相当于C语言中的return。
那么,在catch中抛出的异常必然需要在外层的try…catch…中捕获。
但是,我们关心的是:为什么要在catch中抛出异常,为什么不直接处理,这样不是多此一举吗?
原因是,在实际工程开发中,我们常常会使用第三方的库。而我们也有自己的私有库。
当然我们编写的代码风格及编码要求必须按照我们自己规定的编写。
但对于我们使用者来说,第三方库是不可见的,也就是不可修改的。
那么当我们代码风格和编码要求与第三方库相异时,也就是第三方库抛出的异常类型不适合我们时,我们就需要多加一层try…catch…进行对第三方库的封装,重新抛出异常,而这个异常的类型就能符合我们自己的编码要求了。
示例代码:异常的重新解释
/*
假设: 当前的函数式第三方库中的函数,因此,我们无法修改源代码
函数名: void func(int i)
抛出异常的类型: int
-1 ==》 参数异常
-2 ==》 运行异常
-3 ==》 超时异常
*/
void func(int i)
{
if( i < 0 )
{
throw -1;
}
if( i > 100 )
{
throw -2;
}
if( i == 11 )
{
throw -3;
}
cout << "Run func..." << endl;
}
void MyFunc(int i)
{
try
{
func(i);
}
catch(int i)
{
switch(i)
{
case -1:
throw "Invalid Parameter";
break;
case -2:
throw "Runtime Exception";
break;
case -3:
throw "Timeout Exception";
break;
}
}
}
int main(int argc, char *argv[])
{
// Demo();
try
{
MyFunc(11);
}
catch(const char* cs)
{
cout << "Exception Info: " << cs << endl;
}
return 0;
}