Boost程序库完全开发指南:深入C++”准”标准库(第5版)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.1 smart_ptr库概述

计算机系统中有很多种资源,内存是我们最常用到的资源,此外还有文件描述符、socket、操作系统handle、数据库连接等,在程序中,申请这些资源后必须及时归还,否则会产生难以预料的后果。

3.1.1 RAII机制

为了管理内存等资源,C++程序员通常采用RAII机制(Resource Acquisition Is Initialization,资源获取即初始化),在类的构造函数里申请资源,然后使用资源,最终在析构函数中释放资源。

如果对象是用声明的方式在栈上创建的(一个局部对象),那么RAII机制会正常工作,当离开作用域时,该对象会自动销毁,从而调用析构函数释放资源。

但如果对象是用new操作符在堆上创建的,那么它的析构函数将无法自动调用,程序员必须明确地用对应的delete操作符销毁它,才能释放资源,这就存在着资源泄漏的隐患,因为这时没有任何对象对已经获取的资源负责,如果因某些意外导致程序未能执行delete语句,那么内存等资源就会永久丢失。例如:

new、delete及指针的不恰当运用是C++语言中造成资源获取、释放问题的根源,能否正确地运用delete是区分C++语言新手与熟手的关键。但很多人——即使是熟练的C++程序员,也经常会忘记调用delete。

3.1.2 智能指针

智能指针(smart pointer)是C++群体中热门的议题,围绕它有很多有价值的讨论和结论。它实践了推荐书目[1]中讲解的代理模式,代理了原始“裸”指针的行为,为它添加了更多有用的特性。

向C++引入异常机制后,智能指针由一种技巧升级为一种非常重要的技术,因为如果没有智能指针,程序员必须保证new对象能在正确的时机delete,必须到处编写异常捕获代码以释放资源,而智能指针则可以在退出作用域时(无论是因正常流程离开还是因异常离开)总调用delete来析构在堆上动态分配的对象。

存在很多种智能指针,其中最早的一个应该是C++98标准中的自动指针auto_ptr,它解决了自动释放获取资源的部分问题,例如std::auto_ptr已经在C++标准中被声明为废弃,现在应该使用新的智能指针std::unique_ptr,故本书中不再讲述auto_ptr相关的内容。

auto_ptr的构造函数可以接收new操作符或对象工厂创建出的对象指针作为参数,从而代理原始指针。虽然它是一个对象,但因为重载了operator*和opreator->,其行为非常类似指针,可以把它用在大多数普通指针可用的地方。当退出作用域时(离开函数main或发生异常),C++语言会保证销毁auto_ptr对象,调用auto_ptr的析构函数,进而使用delete操作符删除原始指针,释放资源。

auto_ptr很好用,由于它被包含在C++标准库中,所以可以在世界范围内被广泛使用,这使智能指针的思想和用法深入人心。但auto_ptr存在一些缺陷,所以新的C++标准提供了更完善的unique_ptr、shared_ptr和weak_ptr,而它们正是基于我们接下来要介绍的boost.smart_ptr库的。

boost.smart_ptr库提供了很多种智能指针,常用的有scoped_ptr、shared_ptr、weak_ptr和intrusive_ptr。它们是轻量级的对象,其速度与原始指针相差无几,都是异常安全的(exception safe),而且对于所指向的类型T也仅有一个很小且很合理的要求:类型T的析构函数不能抛出异常。

这些智能指针都位于名字空间boost,需要包含的头文件如下: