三大核心智能指针详解

1. std::unique_ptr (独占所有权)

作为最常用且性能最优的智能指针,它确保资源在同一时间仅被一个指针持有。

特性:

  • 禁止拷贝:不支持拷贝构造函数和赋值运算符
  • 支持移动:可通过std::move()实现所有权转移
  • 零开销:内存占用与原始指针相同,无运行时性能损失

实现原理:封装原始指针并在析构时调用delete,通过禁用拷贝构造函数确保独占性。

2. std::shared_ptr (共享所有权)

允许多个指针共享同一对象资源。

核心机制:

  • 引用计数:采用原子操作的引用计数机制
    • 新增指针时计数+1
    • 指针销毁或重定向时计数-1
    • 计数归零时自动释放内存

底层结构:

  • 包含两个指针成员:
    1. 指向目标对象的原始指针
    2. 指向控制块的指针(存储引用计数、弱引用计数及删除器)

注意:虽然引用计数操作是线程安全的,但对象访问本身不具备线程安全性。

3. std::weak_ptr (弱引用)

专为配合shared_ptr设计,解决循环引用问题。

特性:

  • 不增加引用计数,仅作观察
  • 需通过lock()方法转为shared_ptr才能访问对象
  • 典型应用:环形结构、缓存系统、观察者模式

循环引用问题及解决方案

问题表现:当两个对象通过shared_ptr相互持有时,引用计数无法归零导致内存泄漏。

解决方案:将其中一方的引用改为weak_ptr,打破强引用循环。

std::move与智能指针的配合

  • unique_ptr仅支持移动语义
  • shared_ptr移动操作转移所有权(计数不变),拷贝操作才增加计数
  • 容器存储推荐使用std::move以减少引用计数操作开销

智能指针使用指南

最佳实践原则

  1. 首选 unique_ptr

    • 在不需要共享所有权的情况下,优先使用 unique_ptr(性能最优)
  2. 使用 make_ 系列函数

    • 推荐使用 std::make_unique 和 std::make_shared
    • 优势:异常安全且效率更高
  3. 指针管理规范

    • 避免直接管理 new 分配的指针
    • 分配后应立即存入智能指针

接口设计规范

  1. 常规对象访问

    • 当函数仅需使用对象但不改变所有权时:
      • 传递 T&(原始引用)
      • 传递 T*(原始指针)
  2. 共享所有权场景

    • 当函数需要共享所有权时:
      • 传递 std::shared_ptr<T>
  3. 所有权转移

    • 当函数需要接收所有权时:
      • 传递 std::unique_ptr<T>&&(右值引用)
      • 或按值传递 std::unique_ptr<T>

三指针对比总结

类型 所有权 引用计数 拷贝能力 主要用途
unique_ptr 独占 仅移动 资源独占管理、轻量级场景
shared_ptr 共享 原子计数 可拷贝 共享生命周期、多线程环境
weak_ptr 无所有权 弱引用计数 可拷贝 观察生命周期、解决循环引用

更多推荐