为防止资源泄漏,请使用 RAII 对象,它们在构造函数中获得资源并在析构函数中释放资源
- 两个常被使用的 RAII classes 分别是 tr1::shared ptr 和 auto_ptr。前者通常是较佳选择,因为其 copy 行为比较直观。若选择 auto_ptr ,复制动作会使它(被复制物)指向 null
什么是资源?资源就是,一旦用了它,将来必须还给系统。我们最常使用的资源就是动态分配内存(如果你分配内存却不归还它,会导致内存泄漏),但内存只是你必须管理的众多资源之一,不要思维定式。其他常见的资源还包括
- 文件描述器(file descriptors)
- 互斥锁(mutex locks)
- 图形界面中的字型和笔刷
- 数据库连接
- 网络 sockets
不论哪一种资源,重要的是,当你不再使用它时,必须将它还给系统。
把资源放进对象内,我们便可依赖 C++的“析构函数自动调用机制”确保资源被释放。
以对象管理资源的两个关键点:
- 获得资源后立刻放进管理对象(managing object)内。实际上“以对象管理资源”的观念常被称为“资源取得时机便是初始化时机”( Resource Acquisition Is Initialization;RAII),因为我们几乎总是在获得一笔资源后于同语句内以它初始化某个管理对象。
- 管理对象(managing object)运用析构函数确保资源被释放。不论控制流如何离开区块,一旦对象被销毁(例如当对象离开作用域)其析构函数自然会被自动调用,于是资源被释放。如果资源释放动作可能导致抛出异常,条款8告诉我们怎样解决这个问题。
由于 auto_ptr 被销毁时会自动删除它所指之物,所以一定要注意不能让多个 auto_ptr 指向同一个对象。为了预防这个问题,当两个 auto_ptr 对象之间发生赋值操作时,所有权被转移,这意味着失去所有权的对象被设置为 null。由于 auto_ptr “诡异”的复制行为,auto_ptr 不能应用于 STL 容器上
。
auto_ptr 的替代方案是“引用计数型智慧指针"(reference-counting smart pointer,RCSP)。RCSP 会持续追踪共有多少对象指向某笔资源,并在无人指向它时自动删除该资源。 RCSPS 提供的行为类似垃圾回收(garbage collection),不同的是 RCSPS 无法打破环状引用(cycles of references,例如两个其实已经没被使用的对象彼此互指,因而好像还处在“被使用”状态)。
auto_ptr 和 tr1::shared_ptr 都在其析构函数中做 delete 而不是 delete [],这意味着在动态分配而得的数组身上使用它们是个馊主意。
std::auto_ptr<std::string> aps(new std::string[10]); //馊主意,会用上错误的delete形式
std::tr1::shared_ptr<int> spi(new int[1024]);