C++ 智能指针:auto_ptr / unique_ptr / shared_ptr / weak_ptr 原理与使用

头文件:<memory>,核心思想:RAII,自动管理堆内存,避免内存泄漏。

一、auto_ptr(C++98,已废弃,不要使用)

特点:拷贝时转移资源所有权

复制代码
auto_ptr<Date> p1(new Date);
auto_ptr<Date> p2 = p1; // p1把资源管理权转移给p2,p1变成空指针

缺陷:拷贝后原指针悬空,极易踩坑。C++11 后被淘汰,工程里禁止使用。

二、unique_ptr 唯一指针(C++11)

核心:不支持拷贝,只支持移动 ,同一时刻只能有一个unique_ptr持有资源。

复制代码
unique_ptr<Date> u1(new Date);
// unique_ptr<Date> u2 = u1; // 编译报错,拷贝构造被delete
unique_ptr<Date> u3 = move(u1); // 移动,u1置空,u3接管资源
  • 原理:把拷贝构造、赋值重载函数 delete,禁用拷贝;

  • 适用场景:资源不需要共享,独占所有权,性能开销几乎和裸指针一样;

  • 支持自定义删除器。

三、shared_ptr 共享指针(C++11)

核心:引用计数,支持拷贝 ,多个shared_ptr共同管理同一块堆资源。

复制代码
shared_ptr<Date> sp1(new Date);
shared_ptr<Date> sp2 = sp1; // 拷贝,引用计数+1

底层结构两块内存:

  1. _ptr:指向管理的资源;

  2. _pcount:引用计数(堆上的 int)。

析构逻辑

  • 拷贝:引用计数++

  • 析构:引用计数--

  • 当计数减到 0 时,delete释放资源 + 释放计数内存。

make_shared推荐优先使用:

复制代码
auto sp = make_shared<Date>(); // 一次性分配资源+计数内存,效率更高

注意:shared_ptr构造函数是explicit,不能隐式类型转换。

shared_ptr 的致命问题:循环引用

双向链表场景:节点 A 存next指向 B,节点 B 存prev指向 A,都用shared_ptr。 两个对象析构时,双方引用计数都只能减到 1,永远不会等于 0,内存泄漏。

复制代码
n1 -> n2
n2 -> n1
两个节点互相持有shared_ptr,资源无法释放

👉 解决方案:weak_ptr

四、weak_ptr 弱指针(C++11)

不参与资源所有权,不增加引用计数 ,专门用来解决shared_ptr循环引用。

  • 不能直接访问资源,没有 RAII;

  • 只能绑定到shared_ptr

  • 调用.lock():返回一个shared_ptr检查资源是否存活 。如果资源已经释放,返回空shared_ptr

改造双向链表: 把next/prevshared_ptr改成weak_ptr。 互相引用时不会增加引用计数,对象析构后计数可以正常减到 0,内存正常释放。

复制代码
struct Node
{
    int val;
    weak_ptr<Node> next;
    weak_ptr<Node> prev;
};

五、通用要点

  1. 智能指针析构默认调用delete释放资源,支持自定义删除器,可以管理数组、文件句柄等;

  2. shared_ptr/unique_ptr支持bool隐式转换:if(sp)判断是否持有有效资源;

  3. 不要把裸指针同时交给多个shared_ptr管理,会造成重复释放。

总结选型

|------------|----------------|-------|--------------------|
| 智能指针 | 拷贝 | 核心原理 | 适用场景 |
| auto_ptr | 转移所有权 | 废弃 | 不要用 |
| unique_ptr | ❌禁止拷贝 ✅支持 move | 独占资源 | 独占所有权,默认首选 |
| shared_ptr | ✅支持拷贝 | 引用计数 | 需要多指针共享资源 |
| weak_ptr | 不持有资源 | 不增加计数 | 解决 shared_ptr 循环引用 |

编码建议:优先用unique_ptr;确需共享再选shared_ptr;存在双向引用 / 环形结构,配合weak_ptr

相关推荐
一木 之林1 小时前
李沐《动手学深度学习》知识卡合集:从 Softmax 回归到房价实战(第24-50集)
开发语言·c++·人工智能
心中有你02141 小时前
Java Swing实现校园最短路径导航系统(Dijkstra算法完整源码+详细解析)
java·开发语言·算法
Alphapeople1 小时前
路径规划算法的python实现
开发语言·python·算法
重生之小比特1 小时前
【Java SE】数组的定义与使用
java·开发语言
旋生万物1 小时前
圈道裂痕——用 Python 验证素数分布的螺旋生成论判据
开发语言·python·数论·素数·cci·可计算数学
keyipatience2 小时前
5种IO模型与阻塞IO,select,poll,epoll,LT和ET模式
linux·服务器·网络·数据结构·c++·算法
汉克老师2 小时前
CSP-J 初赛(以满分为目标):第三十八课《数学与逻辑①——排列还是组合?先搞清楚“选”与“排”》
c++·csp-j·小学生·学c++编程
qeen872 小时前
【C++】智能指针介绍
开发语言·c++·笔记·指针
Lionel_Coder2 小时前
matmul 总体设计
c++