异常是一个在程序运行时出现问题的表现。
throw用来抛出异常,当执行到一个有问题的代码段时,调用throw()抛出异常,throw ExceptionClass();其中ExceptionClass为用户自定义的异常类,继承自runtime_error类(<stdexcept>),runtime_error类继承自exception类(<exception>)。ExceptionClass类只需定义一个构造函数,这个构造函数将定义有错误信息的字符串传递到基类的构造函数:ExceptionClass() :runtime_error("what exception"){};。另外可以调用what()函数得到异常列表。throw之后的操作数成为抛出操作数,并不一定非要是异常对象,也可以使表达式、整型等等。
try语句定义了一个可能发生异常的代码模块,异常可能出现在try语句中明确提及的代码,也可能是对其他函数调用以及多层嵌套的语句中。
catch语句用来处理异常。注意:在try语句块和catch处理器之间放入代码是一个语法错误;一个catch只有一个参数,即为throw所传的异常:catch(ExceptionClass & my_exception),用逗号隔开的参数列表是一个语法错误;一个try语句后两个catch捕获相同的异常时一个逻辑错误。
异常发生并且被捕获后,程序控制并不会回到异常的抛出点,控制将从try后的最后一个catch语句之后的第一条语句开始。如果try中的代码正常执行,则将跳过catch。如果异常发生在try中但是没有匹配的catch,则拥有该语句的函数会立刻停止执行且程序会试图定位调用函数中封装的try语句块,即堆栈展开。
什么时候使用异常:异常处理用来处理同步错误,发生在一个语句正在执行的时候,包括数组下表越界、运算溢出、除数为0、无效的函数参数和失败的内存分配等。异常处理并不处理异步事件,如磁盘I/O操作、网络信息到来、鼠标键盘点击等。
重新抛出异常:异常处理器catch在接收到异常时,有可能判断出该异常是它不能处理的或者只能部分处理,那么此时异常处理器会异常处理推给另一个异常处理器,采用throw;来重新抛出相同的异常。执行在一个catch处理器之外的空throw语句将导致函数terminate被调用,程序会放弃该异常处理并立即结束。如:
void throwexception(){
try{
throw exception();
}
catch{
throw;
}
}
//主函数
int main(){
try{
throwexception();
}
catch(exception &){
cout<<"接收重新抛出的异常";
}
}
处理意料之外的异常:以下情况会调用terminate函数:1.对于抛出的异常,找不到匹配的catch块;2.析构函数试图在堆栈展开时抛出异常;3.在没有异常要处理时试图重新抛出异常;4.调用unexpected将默认调用terminate。
堆栈展开:当一个函数抛出异常,但是该函数不在try...catch语句块内时就会发生堆栈展开,试图在该函数的调用端寻找可以捕获异常的catch块。如果调用端也不在try...catch语句块内,则继续返回更深层次的调用端,直到返回最初调用该函数的语句,而返回后途经函数的局部变量将被销毁,如果最终都没找到一个try...catch语句块,则将调用terminate。
处理new失败:C++标准指出,当遇到new失败抛出bad_alloc异常,它包含在<new>中。在new操作失败后自动抛出bad_alloc异常,通过catch(bad_alloc &)接收。另一个处理new失败的函数是set_new_handler,该函数的参数是一个指向没有参数且返回值为空的函数的指针。在new失败后便会调用该指针指向的函数,不管异常发生在什么地方都会调用之。
标准库异常类层次: