C++: 智能指针

在使用传统指针的 C++ 编程中,我们经常遇到申请空间忘记释放或重复释放,甚至难以确定空间此时是否应该释放的问题。

智能指针可以实现资源的自动回收。它将普通的指针封装成一个对象。于是,在对象生命周期结束时,其所管理的内存也会被考虑释放。

C++ 提供三种智能指针:unique_ptr 用于管理所有权不可共享的对象,shared_ptr 用于管理可被共享的对象,weak_ptr 用于协助 shared_ptr 进行共享资源管理,但本身并不“参与”共享,只作为“旁观者”,收集资源的使用情况而不影响资源的共享状态。

滥用智能指针对代码的可读性会造成显著影响。因此,在使用智能指针前,需要酌情考虑,是否真的需要使用动态分配,是否能明确资源的所有权,为什么不采用非动态的值语义对象或普通引用。同时,还应当考虑到接口设计的兼容性和额外的性能开销。

unique_ptr

unique_ptr 用于管理所有权互斥(exclusive ownership)的资源,即资源只能同时被一个实例拥有,只能被一个智能指针指向。

资源的创建通过 std::make_unique<T>() 完成。需要数组可直接将 T 改为 T[]。指针操作的各种运算符都已被重载,可以很方便地使用。

unique_ptr 拒绝复制语义但允许移动语义。移动通过 std::move 完成,从 ptrAptrB 的移动操作会使 ptrB 拥有 ptrA 原先持有的资源,并导致 ptrA 成为空指针。这种特性可以用于方便而高效的实现工厂函数。

shared_ptr

shared_ptr 用于管理所有权共享的资源。资源可以被多个实例同时拥有。这种共享所有权的管理通过引用计数实现。系统会为资源维护一个控制块,其中有引用计数等信息。当某个 shared_ptr 释放时,发现引用计数归零,则释放这块资源。

不同于 unique_ptrshared_ptr 无法直接管理数组,需要通过诸如手工指定自定义删除器等方式。但如此费劲,不妨考虑以容器代之。

shared_ptr 的拷贝构造、赋值运算均采用复制语义。std::move 仍然可以被用于实现所有权转移。

weak_ptr

weak_ptr 类似 shared_ptr,但它不会改变引用计数,也不能防止资源被释放。

weak_ptr::lock() 方法可以尝试通过一个 weak_ptr 创建 shared_ptr。若资源已经被释放,则创建将会失败。

weak_ptr 的一个经典用途是解决只有 shared_ptr 时两个对象互相持有(作为成员的)指向对方的强引用,造成的循环引用问题。破环的一种手段,就是将其中一个 shared_ptrweak_ptr 代之。

我们可以用类似的想法去构建一棵树。父节点持有子节点们的 shared_ptr,而子节点持有父节点的 weak_ptr。此时,若释放父节点,则它子树内的所有节点应当都被释放。

上一篇:Weak Pair HDU - 5877 T14 D57


下一篇:Python 使用sys.exc_info自己捕获异常详细信息