学习C++的时候就没有怎么重视异常这部分知识,后来知道也基本没有看到C++项目里面用try/catch的。google编程规范中甚至直接说明不使用C++这个特性,所以我一直都没搞明白这个“简单的”try/catch。
查阅《C++编程思想》,我记录以下一些内容。首先是C语言的一些错误处理方法。
1) 出错信息可通过函数的返回值获得。如果函数返回值不能用,则可设置一全局错误判断标志(标准 C语言中 errno( )和perror( )函数支持这一方法)。由于对每个函数调用都进行错误检查,这十分繁琐并增加了程序的混乱度。程序设计者可能简单地忽略这些出错信息,因为乏味而迷乱的错误检查必须随着每个函数调用而出现。另外,来自偶然出现异常的函数的返回值可能并不反映什么问题。这中方法异常处理方法在Linux内核里面非常见,甚至可以说是标准的做法。根据函数的返回值判断函数的执行结果,再结合一大堆的goto语句,实现错误处理(比如说资源的释放)。比较常见的是资源申请的情况,如果资源数量比较多,就会出现程序逻辑复杂。goto语句很容易就把你搞得头大。2) 可使用 C标准库中一般不太熟悉的信号处理系统,利用signal()函数(判断事件发生的类型)和raise()函数(产生事件)。由于信号产生库的使用者必须理解和安装合适的信号处理系统,所以应紧密结合各信号产生库,但对于大型项目,不同库之间的信号可能会产生冲突。这种方法的缺陷更明显了,用户信号是有限的,虽然可以更换处理函数。但是冲突是几乎不可避免的,你怎么知道会不会有两个错误同时发生了,结果有一个错误信号就被忽略了。
3) 使用 C标准库中非局部的跳转函数: setjmp( ) 和 longjmp( )。 setjmp( ) 函数可在程序中存储一典型的正常状态,如果进入错误状态, longjmp( )可恢复setjmp( ) 函数的设定状态,并且状态被恢复时的存储地点与错误的发生地点紧密联系。说实话我貌似是第一次明白这东西的作用,汗!(不过现在习惯了,std::bind什么的现在也都不知道!)。下面是一个例子:其实就是抄了下书上的代码。
#include <iostream>
#include <setjmp.h>
using namespace std;
class rainbow {
public:
rainbow() { cout<<"rainbow()"<<endl;
}
~rainbow() {
cout<<"~rainbow()"<<endl;
}
};
jmp_buf kansas;
void OZ()
{
rainbow RB;
for(int i=0;i<3;i++)
{
cout<<"there is no place like home\n";
}
longjmp(kansas, 47);
//这里的value是回到setjmp位置时,setjmp的返回值。如果设置为0,则返回值是1
}
int main()
{
if(setjmp(kansas) == 0) {
cout<<"tornado, witch, munchkins...\n";
OZ();
}else {
cout<< "Auntie Em! "
<< "I had the strangest dream...\n"
<<endl;
}
}
至于C++的异常语法,其实大家都是知道的。但是它是如何实现的呢?这一直是一个疑问。后来我看了白杨的《C++异常机制的实现方式和开销分析》
传送门,确实有茅塞顿开的感觉,推荐一下。