C++的异常处理
C++中的异常处理机制由try、throw、catch组成。
try
语句块负责监视异常;
throw
语句用于异常信息的发送,也称为抛出异常;
catch
语句用于异常的捕获,并作出相应的处理。
代码结构如下:
try
{
// 执行代码
throw 表达式;
}
catch(异常类型)
{
// 处理代码
}
catch(异常类型)
{
// 处理代码
}
throw语句抛出一个异常,异常是一个表达式,其值的类型可以是基本类型,也可以是类。
catch可以有多个,但至少要有一个。
如果希望不管抛出哪种异常都能捕获,则可以这样编写catch块:
catch(...)
{
// 处理代码
}
代码的执行过程
首先执行try块中的语句,
- 如果执行的过程中没有异常抛出,那么所有catch块中的语句都不会被执行,直接跳转到最后一个catch块后面继续执行;
- 如果抛出了异常,则立即跳转到第一个与抛出的异常类型匹配的catch块中执行,执行完之后跳转到最后一个catch块后面继续执行。
代码示例:
try
{
int v1 = 10;
if (v1 != 0)
{
throw -1; // 抛出int类型异常
}
}
catch (int e)
{
cout << e << endl;
}
// 程序运行结果为:-1
异常的再抛出:
如果一个被调函数在执行过程中抛出的异常在本函数内就被catch块捕获并处理,那么该异常就不会抛给主调函数;如果异常在被调函数中没有被处理,那么就会抛给主调函数。
如果一层层的函数都不处理异常,异常最终会抛给最外层的main函数,如果main函数也不处理,那么程序就会立即异常中止。
函数的异常声明列表:
C++允许在函数声明和定义时,在后面加上该函数所能抛出的异常列表,如下:
//这两句表示该函数可能会抛出 int,double,A,B,C 类型的异常。
void func() throw(int,double,A,B,C);
void func() throw(int,double,A,B,C){...}
void func() throw(); //这种表明函数不会抛出任何异常
void func(); //表明该函数可以抛出任何类型的异常
C++标准异常类:
C++ 标准库中有一些类代表异常,这些类都是从 exception 类派生而来的。
使用它们需要包含头文件:#include <stdexcept>
C++程序在遇到某些异常时,即使程序中没有写throw语句,也会自动抛出上述异常类的对象。这些异常类都有成员函数what(),用于返回字符串形式的异常描述信息。
示例:
try
{
char * p = new char[0x7fffffff]; //无法分配这么多空间,会抛出异常
}
catch (bad_alloc & e)
{
cerr << e.what() << endl;
}
// 程序运行结果为:bad allocation
- bad_typeid:使用typeid运算符时,如果操作数是一个多态类的指针,但是指针的值为NULL,则会抛出该异常。
typeid运算符用来获取一个表达式的类型信息,它的操作对象既可以是表达式,也可以是数据类型。
它会把获取到的类型信息保存到一个type_info类型的对象里,并返回该对象的常引用。
eg:
int n = 100;
const type_info &nInfo = typeid(n);
cout << nInfo.name() << endl;
程序运行结果为:int
- bad_cast:在用 dynamic_cast 进行从多态基类对象(或引用)到派生类的引用的强制类型转换时,如果转换是不安全的,则会拋出此异常。
- bad_alloc:在用new操作符进行动态内存分配时,如果分配失败,则会抛出磁异常。
- ios_base::failure:io过程中出现的异常。
- logic_error:逻辑错误。
- out_of_range:用vector或string的at()成员函数根据下标访问元素时,如果下标越界,则会抛出此异常。
- runtime_error:运行时错误。