什么是 C++ 智能指针

发布时间:2026/6/29 7:00:01
什么是 C++ 智能指针 C11 标准模板库STL引入了现代 C 中管理动态内存的核心工具——智能指针。它们位于memory头文件中。智能指针旨在解决 C 裸指针带来的手动内存管理问题如内存泄漏、悬垂指针、异常安全等。智能指针的行为类似于普通指针但能够自动释放所拥有的对象是 RAII资源获取即初始化思想的典型应用。C 标准库提供了三种主要的智能指针std::unique_ptr、std::shared_ptr和std::weak_ptr以及已被废弃的std::auto_ptr。下面分别介绍它们的特性、适用场景和注意事项。1. std::unique_ptr—— 独占所有权所有权模型严格独占。一个std::unique_ptr实例唯一拥有它所指向的对象不允许复制构造或复制赋值但支持移动语义所有权可转移。默认删除器调用delete也可为数组特化std::unique_ptrT[]或自定义删除器。开销与裸指针几乎相同无额外引用计数开销。std::unique_ptr 典型使用场景替代裸指针任何需要动态分配并拥有唯一所有权的资源。工厂函数返回动态创建的对象的独占所有权。容器元素如std::vectorstd::unique_ptrWidget安全地存储多态对象。自定义资源管理通过自定义删除器管理文件句柄、数据库连接等比如std::unique_ptrFILE, decltype(fclose)。std::unique_ptr 示例std::unique_ptr 注意事项优先使用std::make_uniqueC14而不是直接new更安全、异常安全且性能略优。需要传递所有权时使用std::move。如果只需要在函数内部使用动态对象首选std::unique_ptr开销最低。2. std::shared_ptr—— 共享所有权所有权模型多个std::shared_ptr可共享同一对象内部使用引用计数来跟踪所有者数量。当最后一个std::shared_ptr被销毁或重置时对象被删除。线程安全引用计数的操作是原子性的但指向的对象本身不是线程安全的需要额外同步。删除器自定义删除器不会改变类型参数但会影响构造方式。std::shared_ptr 典型使用场景多个对象或组件需要共同拥有同一资源且无法确定哪个会最后释放。缓存多个客户端共享缓存对象当所有客户端不再需要时自动释放。多线程任务在线程间传递并共享数据避免过早释放。与std::weak_ptr配合实现弱引用解决循环引用问题。std::shared_ptr 示例std::shared_ptr 注意事项循环引用如果两个std::shared_ptr互相持有例如双向链表中的next和prev引用计数永远不为 0导致内存泄漏。解决方案将其中一个改为std::weak_ptr。性能开销比std::unique_ptr大需要维护引用计数通常两个机器字一个指针一个控制块指针。尽量使用std::make_shared将对象和控制块一起分配提高内存局部性且更安全但如果自定义删除器且需要std::weak_ptr则不能使用std::make_shared。避免使用裸指针构造多个std::shared_ptr会导致未定义行为出现双重删除。3. std::weak_ptr—— 弱引用不增加引用计数定位配合std::shared_ptr使用不参与所有权。它指向一个由std::shared_ptr管理的对象但不会增加引用计数。访问方式不能直接解引用必须通过lock()获得一个std::shared_ptr然后判断是否为nullptr如果是表示对象已被释放。用途解决循环引用、观察者模式中避免共享所有权、安全地缓存弱引用。std::weak_ptr 典型使用场景打破循环引用例如父子结构中父持有子的std::shared_ptr子持有父的std::weak_ptr。观察者模式主题持有观察者的std::weak_ptr避免主题阻止观察者销毁。缓存例如一个缓存池键为std::weak_ptr允许对象在无人使用时自动被回收。std::weak_ptr 示例打破循环引用std::weak_ptr 注意事项std::weak_ptr不能直接管理数组但可通过自定义删除器间接实现。每次使用lock()都会构造一个新的shared_ptr有一定开销如果已知对象仍存活且不会在线程间被释放可以先用expired()检查但实际使用时仍需lock()保证安全。4. 已废弃std::auto_ptrC98/03它是 C11 之前的标准库中首个智能指针具有所有权转移语义复制操作会转移所有权原指针变为空。缺陷由于其诡异的复制行为不能放入容器且不兼容