C++:异常机制

异常机制简介:

 语法:

try{
    throw exp;
}
catch (Exp exp){
    ...
}

1. 在需要抛出异常的代码段外用try包裹住。

2. 在try内部,需要抛出异常的地方调用 ‘throw + 表达式’,程序不再执行throw后面的代码,直接跳转到catch处,与catch处进行类型匹配,成功则执行catch处代码。

3. catch内部执行完后继续执行catch后续的代码。

 

  异常对象:

通过throw关键字抛出的表达式为一个异常对象。

1. 异常对象在throw后会被复制拷贝一份到一个特殊的区域,即TIB区,为所有catch语句可以访问的空间。

2. 由于异常对象会被拷贝,则异常对象应有共有的拷贝构造函数和析构函数。、

3. 由于会拷贝异常对象的数据类型,所以抛出的对象不能是指针或引用,否则在使用时对象本身已被销毁,跟函数对象类似。

4. 异常对象的析构是在catch语句处理完后析构的。

 

  catch过程:

1. catch的参数如果是引用,则会直接更改异常对象;如果是值传递,则会再次进行拷贝。

2. 在catch匹配异常对象类型的过程中不会做任何隐式的转换。除非以下情况:

  a. 非const转const,const转非const。

  b. 允许派生类到基类的转换,即允许基类捕获派生类;但不允许派生类捕获基类。

  如果用基类的值传递来catch派生类的对象,则会发生派生类的截断。用引用则不会。

 

3. 在catch匹配时并不是按照最匹配的,而是匹配最先可以匹配到的。

4. 如果在catch中没有处理好异常,可以接着将异常向外部抛出,此时可以直接使用throw即可,不需要加异常对象。

5. catch (...) 可以捕获所有的异常,应该放在所有catch最后。

 

 

异常机制与构造析构函数:

1. 在析构函数中不应抛出异常,否则程序将会终止;应该在析构函数内部处理异常。

 

noexcept关键字

作用:防止异常的传播,提高安全性

c++11 用noexcept关键字修饰函数,表明这个函数不会抛出异常。

这个禁止抛异常的检查是在运行时期,而不是在编译时期。

任然可以在声明noexpect函数内部写throw的语句,只是在运行时会直接中止程序。

 

异常机制的好处

1. 统一地进行错误处理,由于异常机制会使代码直接跳转到统一的地方,不需要一层层返回函数。

2. 更加灵活丰富的错误信息,错误信息直接是以对象的形式抛出,可以方便的涵盖更多的信息。

3. 使不应该被忽略的逻辑错误通过抛异常强制终止程序,提高了程序的健壮性。

 

异常机制的坏处

增加了程序的开销:

为了实现代码跳转后,调用堆栈中临时变量的正常析构,需要在每个函数体内记录一些表格,和throw语句所在的偏移量。还有寻找catch匹配的一些信息。

 

异常与线程

在c++11之前,异常是没有办法跨线程传递的。c++11之后的一些语法特性给跨线程传递异常提供了可能。

C++11之前需要在各个线程内部做catch来捕获异常。

C++11之后:

Future

标准库提供了一些工具来获取异步任务(即在单独的线程中启动的函数)的返回值,并捕捉其所抛出的异常。这些值在共享状态中传递,其中异步任务可以写入其返回值或存储异常,而且可以由持有该引用该共享态的 std::future 或 std::shared_future 实例的线程检验、等待或是操作这个状态。

详见下一篇介绍std::future

posted @ 2021-05-10 10:40  Dylan_Liang  阅读(177)  评论(0编辑  收藏  举报