《C++ Primer》第十八章 用于大型程序的工具

大规模编程对程序设计语言的要求更高,大规模程序的特殊要求包括:在独立开发的子系统之间协同处理错误的能力,使用各种库进行协同开发的能力,对比较复杂的应用概念建模的能力。

异常处理

异常机制使我们能够将问题的检测与解决过程分离开。

C++通过抛出一个表达式来引发一个异常,throw Exception()。被抛出的表达式的类型和当前的调用链共同决定由哪段异常处理代码来处理该异常。根据抛出的对象,程序抛出异常部分将告知异常处理部分到底发生了什么。当执行throw后,控制权将转移到与之匹配的catch模块中,这有两个重要的含义,沿着调用链的对象可能提早退出,程序开始执行异常处理代码时沿着调用链创建的对象将被销毁。

当抛出一个异常后,程序会沿着调用链一直查找可用的catch语句,整个查找的过程称为栈展开。如果一直查找但是没有找到可以捕获异常的语句,则程序将终止。如果在栈展开过程中退出了某个块,编译器负责销毁该块中创建的局部对象,如果局部对象是类类型,对象的析构函数将被自动调用。

在栈展开的过程中,在构造函数中或容器的初始化过程中要特别注意处理,要保证已经初始化的成员能被正确销毁。

栈展开的过程中析构函数将被自动执行,因此在析构函数中不应抛出不能被它自身处理的异常。一旦在栈展开的过程中析构函数抛出了异常并且析构函数没有捕获到该异常,则程序将立即终止。所有标准库析构函数都保证不会抛出异常。

异常对象是一种特殊的对象,编译器使用异常抛出表达式对异常对象进行拷贝初始化,如果该表达式类型是数组类型或函数类型,则表达式将被转换为指针类型。异常对象位于编译器管理的空间,编译器确保异常处理程序能访问到该对象,并且在处理结束后销毁该对象。抛出一个指向局部对象的指针肯定是错误的,因为在栈展开的过程中该局部对象被销毁,这如同函数返回一个指向局部对象的指针道理相同。

当抛出一个表达式时,该表达式的静态编译时类型决定了异常对象的类型。如果一个throw解引用一个基类指针,而该指针指向的是一个派生类的对象,则抛出的对象将被切掉。

catch子句中的异常声明与函数形参列表类似,如果不需要访问抛出的异常对象的话,可以省略形参名称。声明的类型决定了处理代码所能捕获的异常类型。当进入一个catch语句后,将使用异常对象初始化异常声明的参数,与函数参数类似,如果catch的参数是非引用类型,则该参数是异常对象的一个副本。

catch的异常声明与函数参数另一个相似的特性是,如果声明类型是基类类型,则可以捕获其派生类的异常对象。此时,如果catch的类型是非引用类型,则异常对象将被切掉,如果是引用类型,将以常规的方式绑定到异常对象上。

特别注意,catch异常声明的静态类型决定catch语句所能执行的操作。通常情况下,如果catch接受的异常与某个继承体系相关,最好把参数声明为引用类型。

搜寻catch的过程将按照其出现的顺序进行,因此最终找到的catch未必是最佳的异常匹配,因此在有异常对象存在继承关系时应仔细规划catch的出现顺序。

在catch子句中可以重新抛出异常,通过throw空语句进行重新抛出。throw空语句只能出现在catch子句或通过catch字句调用的函数中,如果在catch处理代码之外遇到throw空语句,程序将直接terminate。

catch(...)可以捕获所有异常,如果与其他catch语句同用,必须保证catch(...)在最后出现。

构造函数在进入函数体之前首先执行初始值列表,因此构造函数体内的catch语句无法处理初始值列表中抛出的异常。将构造函数写成函数try语句块的形式可以捕获构造函数体中的异常也可以捕获初始值列表中的异常。try写在函数体和初始值列表的冒号前面,catch写在函数体括号的后面。在初始化构造函数的参数时发生的异常不属于函数try语句块,应该由调用函数的上下文处理。处理构造函数初始值列表异常的唯一方法是将构造函数写成函数try语句块的形式。

通过noexcept说明可以指定某个函数不会抛出异常,noexcept要出现在该函数的所有声明语句中和定义语句中,如果函数声明了noexcept但是却抛出了异常,则程序将直接终止。noexcept接受一个可选的类型为bool的实参,true表示不会抛出异常,false表示可能抛出异常。

noexcept运算符用来判断表达式是否会抛出异常,和sizeof类型,noexcept不会计算表达式的值。

noexcept会影响函数指针。如果虚函数承诺不会抛出异常,则后续派生出来的虚函数也必须不会抛出异常。

标准库构成了一个异常层次结构,通常一个较大型的程序会有自己的异常层次结构。

posted @ 2018-11-24 08:21  Jeff-Lee  阅读(146)  评论(0编辑  收藏  举报
2047179505-asdf123456/*-