使用异常机制通报越界访问错误是函数检查实参的一个示例,此时,因为基本假设,即所谓的前置条件(precondition)没有满足,所以函数将拒绝执行。在正式地说明Vector的下标运算符时,我们应该规定类似于“索引值必须在[0:size())范围内”的规则,这一规则在operator[]()内被检查。记号[a:b)指定了一个半开区间,其中a位于区间内而b不在。无论什么时候只要我们试图定义一个函数,就应该考虑它的前置条件是什么,以及检验该条件的过程是否足够简洁。
然而在上面的定义中,operator[]()作用于Vector的对象并且只在Vector的成员有“合理”的值时才有意义。特别是,我们说过“elem指向一个含有sz个double型元素的数组”,但这只是注释中的说明而已。对于类来说,这样一条假定某事为真的声明称为类的不变式(class invariant),简称为不变式(invariant)。建立类的不变式是构造函数的任务(从而成员函数可以依赖于该不变式),它的另一个作用是确保当成员函数退出时不变式仍然成立。不幸的是,我们的Vector构造函数只履行了一部分职责。它正确地初始化了Vector成员,但是没有检验传入的实参是否有效。考虑如下情况:

这条语句很可能会引起混乱。
与原来的版本相比,下面的定义更好:

本书使用标准库异常length_error报告元素数目为非正数的错误,因为一些标准库操作也是这么做的。如果new运算符找不到可分配的内存,就会抛出std::bad_alloc。我们可以接着书写:

你可以自定义异常类,然后让它们把任意信息从检测异常的点传递到处理异常的点(见3.4.1节)。
通常情况下,当遭遇异常问题之后函数就无法继续完成工作了。此时,“处理”异常的含义仅仅是做一些简单的局部资源清理,然后重新抛出异常。要想在异常处理模块中抛出(重新抛出)异常,只需书写throw;例如:
不变式的概念是设计类的关键,而前置条件也在设计函数的过程中起到类似的作用。不变式能够:
帮助我们准确地理解想要什么;
强制我们具体而明确地描述设计,而这有助于确保代码正确(在调试和测试之后)。
不变式的概念是C++中由构造函数(见第4章)和析构函数(见4.2.2节,11.2节)支撑的资源管理概念的基础。