C++:异常
一、异常介绍
在C中,传统的异常处理机制有两种:
- assert断言。比如程序发送段错误时,会触发assert,导致程序直接退出。
- 错误码。程序异常返回错误码,虽然每种错误码背后对于一类错误,但程序员还是无法明确错误原因,以及错误位置,需要程序员自身去查找!
所有C++引入了异常机制。当一个函数发生无法处理的错误后,会抛出异常,让函数的直接或间接调用者对该异常进行捕获处理!!C++通过throw抛出异常,当一段段程序可能抛出错误,捕获异常的方式采用try和catch关键字。其中try中存放可能抛出异常的代码,而try中的代码也被称为保护代码;而catch则是对异常机进行捕获,并进行处理!!
try
{
// 保护的标识代码
}catch( ExceptionName e1 )
{
// catch 块
}catch( ExceptionName e2 )
{
// catch 块
}catch( ExceptionName eN )
{
// catch 块
}
二、异常的使用
1)、异常抛出和匹配规则
异常是通过throw抛出对象引发的,该对象的类型决定了激活那个catch块的代码。但在调用链中可能存在多个对同一类型的catch模块。所以被选择的处理代码为调用链中与该对象匹配并且距离抛出异常位置最近的那个!被抛出对象,不是直接抛出对象本身,而是抛出该对象的拷贝副本(原因在于抛出的可能是一个临时对象)
catch捕获异常时,捕获的类型和抛出对象的类型要相同。但也有例外,即我们可以通过catch一个父类,对子类抛出对象进行捕获!通过C++中提供了catch(…)用于捕获任意异常,但该方式无法得知异常错误是啥!!
2)、函数调用链中异常栈的展开匹配规则
抛出异常后,编译器首先会检查throw本身是否在try内部,如果在编译器会查找符合要求的catch语句,然后直接跳到目标catch语句执行catch中的代码!
如果当前函数栈中不存在,此时直接退出当前函数的栈,编译器对当前栈进行销毁。然后在调用函数的栈中继续查找匹配合适的catch语句。如果到达main函数的栈中还没有查找到合适的catch语句,此时编译器会直接终止程序!
一旦编译器查找到合适的catch语句后,编译器会直接从抛出异常的位置直接调转到catch语句处,执行catch语句中的内容。这也意味着该过程可能会导致一些资源释放错误,导致一系列问题。
3)、异常的重新抛出
有可能单个的catch不能完全处理一个异常,在进行一些校正处理以后,希望再交给更外层的调用链函数来处理,catch则可以通过重新抛出将异常传递给更上层的函数进行处理。
下面有这样一段代码:我们用于计算用户输入的两个值相除结果。当除数为0时,抛出异常。但博主在Func()开始时,先申请一段空间。此时一旦抛出异常,会导致空间资源无法正常释放,导致内存泄漏!!
double Division(int a, int b)
{