异常处理:增强错误恢复能力是提高代码健壮性的最有力的途径之一,C语言中采用的错误处理方法被认为是紧耦合的,函数的使用者必须在非常靠近函数调用的地方编 写错误处理代码,这样会使得其变得笨拙和难以使用。C++中引入了异常处理机制,这是C++的主要特征之一,是考虑问题和处理错误的一种更好的方式。
传统的错误处理和异常处理(c语言中的异常处理):
在函数中返回错误,函数会设置一个全局的错误状态标志;使用信号来做信号处理系统,在函数中raise信号,通过signal来设置信号处理函数,这种方式耦合度非常高,而且不同的库产生的信号值可能会发生冲突。
C语言的异常处理方式:
1.终止程序(除数为0)
2.返回一个表示错误的值,附加错误码(GetLastError())
3.返回一个合法值,让程序处于某种非法的状态(坑爹的atoi())
4.调用一个预先准备好在出现”错误”的情况下用的函数(回调函数)。
5.暴力解决方式:abort()或者exit()
6.使用goto语句
7.setjmp()和longjmp()组合C++中的异常处理方式:
-1.异常的抛出和捕获:
异常是通过抛出对象而引发的,该对象的类型决定了应该激活哪个处理代码。
被选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最的那一个。
抛出异常后会释放局部存储对象,所以被抛出的对象也就还给系统了, throw 表达式会初始化一个抛出特殊的异常对象副本(匿名对象),异常对象由编译管理,异常对象在传给对应的 catch 处理之后撤销。
异常的抛出:
throw 必须在 try 代码块中.后边跟的值决定抛出异常的类型。
try
{
throw E();
}
catch (H h)
{}
-2.栈展开
抛出异常的时候,将暂停当前函数的执行,开始查找对应的匹配catch子句。
首先检查throw本身是否在try块内部,如果是再查找匹配的catch语句。如果有匹配的,则处理。没有则退出当前函数栈,继续在调用函数的栈中进行查找。
不断重复上述过程。若到达main函数的栈,依旧没有匹配的,则终止程序。
上述这个沿着调用链查找匹配的catch子句的过程称为栈展开。
找到匹配的catch子句并处理以后,会继续沿着catch子句后面继续执行。
-3异常捕获的匹配规则
异常对象的类型与catch说明符的类型必须完全匹配。只有以下几种情况例外:
允许从非const对象到const的转换;
允许从派生类型到基类类型的转换;
将数组转换为指向数组类型的指针,将函数转换为指向函数类型的指针。
-4异常的重新抛出
class Exception
{
public:
Exception(int errId = 0, const char * errMsg = "")
: _errId(errId)
, _errMsg(errMsg)
{}
void What() const
{
cout << "errId:" << _errId << endl;
cout << "errMsg:" << _errMsg << endl;
}
private:
int _errId; // 错误码
string _errMsg; // 错误消息
};
void Func1()
{
throw string("Throw Func1 string");
}
void Func2()
{
try
{
Func1();
}
catch (string & errMsg)
{
cout << errMsg << endl;
//Exception e (1, "Rethorw Exception");
//throw e ;
// throw;
// throw errMsg;
}
}
void Func3()
{
try
{
Func2();
}
catch (Exception & e)
{
e.What();
}
}
有可能单个的catch不能完全处理一个异常,在进行一些校正处理以后,希望再交给更外层的调用链函数来处理,catch则可以通过重新抛出将异常传递给更上层的函数进行处理。