所有程序都包含一项关键任务:管理资源。所谓资源是指程序中符合先获取后释放(显式或者隐式)规律的东西,比如内存、锁、套接字、线程句柄和文件句柄等。对于长时间连续运行的程序来说,如果不能及时地释放掉资源(即造成了泄漏),就有可能大大降低程序的运行效率甚至造成程序崩溃。即使在规模较小的程序中,资源泄漏也可能造成严重的后果:由于系统资源短缺,所以程序的运行时间会成倍地增长。
标准库组件不会出现资源泄漏的问题。在设计标准库组件时,设计者使用成对的构造函数/析构函数等基本语言特性来管理资源,确保资源依存于其所属的对象,而不会超过对象的生命周期。举一个例子,3.2.1.2节介绍的 Vector就是使用构造函数/析构函数的机制管理元素的,所有标准库容器的实现方式也都与之类似。此外,这种管理资源的方式通常通过抛出和捕获异常来进行错误处理。例如标准库当中的锁:
mutex m; //用于确保共享数据被正确访问//...void f(){uniqe_lock<mutex> lck{m}; //获取资源//操作共享数据}
lck的构造函数首先获取它的 mutex,m(见5.3.4节),然后 thread开始处理,最后析构函数负责释放掉资源。在上面的例子中,当控制线程离开f0时(通过 return语句跳转到函数末尾,或者因为抛出异常而离开函数), unique_lock的析构函数负责释放掉 mutex。
这是“资源获取即初始化”(RAI,见3.2.1.2节和13.3节)技术的一个典型应用。RAIl是C++处理资源的基础,容器(比如 vector和map)、 string和 iostream管理资源(比如文件句柄和缓冲区)的方式都十分相似。
