一 异常处理原则:
C++异常处理机制将异常类型化,比传统错误处理用不同的数字表达不同类型的错误能更包含更多的信息。异常处理机制实际是一种运行时通知机制。异常处理机制的本质是在正真导致错误的语句即将执行之前,因此异常抛出时,正真的错误并未发生。
二 异常类型和异常对象
任何一种类型都可以当做异常类型,即任何一个对象都可以当做异常对象,异常是通过类型来匹配的。
三 异常处理语法结构
异常处理也是一种程序控制结构,它包含4部分:抛异常,提炼异常,捕获异常及异常对象本身。对应C++的三个关键字及结构。throw , catch{} ,try{}. throw 只是一条语句,抛出异常。 try{}可能包含异常抛出的代码。catch{} 是用来捕获异常。catch处理完后不会返回到 throw这里,它要么退出函数,要么执行后面正常的与语句,有些类似于goto。每一个try块后面必须至少跟一个catch块。当异常抛出时,C++处理机制将从碰到的第一个catch开始匹配,直到找到类型符合的catch块。
异常对象看上去像是局部对象,但它其实是创建在专用的异常堆栈上,因此才可以跨越多个函数传递到上层,否则在堆栈清退时就会被销毁。
四 异常捕获匹配规则
异常对象的类型与catch说明符的类型必须完全匹配。 只有以下几种情况例外
1. 允许从非const对象到const的转换。
2. 允许从派生类型到基类类型的转换。
3. 将数组转换为指向数组类型的指针,将函数转换为指向函数类型的指针。
下面的是从派生类到基类类型的转换代码。
#include <iostream>
#include <string>
using namespace std;
class Exception
{
public:
Exception(int id = 0, const char* msg = "")
:_errId(id)
, _errMsg(msg)
{}
virtual const char* What() = 0;
int GetErrId()
{
return _errId;
}
protected:
int _errId;
string _errMsg;
};
class OutOfRange : public Exception
{
public:
OutOfRange(const char* msg = "")
:Exception(1, msg)
{}
virtual const char* What()
{
_errMsg += "越界";
return _errMsg.c_str();
}
};
class BadAlloc : public Exception
{
public:
BadAlloc(const char* msg = "")
:Exception(2, msg)
{}
virtual const char* What()
{
_errMsg += "申请内存失败";
return _errMsg.c_str();
}
};
class OverFlow : public Exception
{};
template<class T, size_t N = 100>
class Array
{
public:
T& operator[](size_t index)
{
if (index >= N)
{
throw OutOfRange(__FUNCTION__);
}
return _a[index];
}
protected:
T _a[N];
};
// new[]
template<class T>
T* NewArray(size_t N)
{
T* p = (T*)malloc(sizeof(T)*N);
if (p == 0)
{
//throw BadAlloc("模拟实现new[]的NewArray抛异常");
throw BadAlloc(__FUNCTION__);
}
for (size_t i = 0; i < N; ++i)
{
new(p + i)T();
}
return p;
}
#include <vector>
int main()
{
//第一个catch会捕获OutOfRange,显示越界错误
//try
//{
// // vector
// Array<int, 10> a1;
// a1[0] = 0;
// a1[10] = 10;
// // new new[]
// string* p = NewArray<string>(10);
// char* p1 = NewArray<char>(0x7fffffff);
//}
//catch (Exception& e)
//{
// cout<<e.What()<<endl;
//}
//第二个catch会捕获BadAlloc
try
{
char* p1 = new char[0x7fffffff];
vector<int> v1;
v1[1] = 0;
}
catch(exception& e)
{
cout<<e.what()<<endl;
}
system("pause");
return 0;
}
五 异常的优缺点
优点:
1比传统返回错误码的方式更清晰的表示程序的错误信息。
2很多C++的第三方库会使用异常,使用异常能更好地用库。
3引用异常能更好地测试代码,入框架测试。
缺点:
1异常的语法结构会导致执行乱跳,不利于跟踪调试。
2异常安全问题,需要更好地使用RAII编写异常安全代码,如智能指针。