😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍 C++ 智能指针🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭
⏰发布时间⏰: 2025-05-16 12:19:44
本文未经允许,不得转发!!!
目录
- 🎄一、概述
- 🎄二、核心成员函数详解
- ✨2.1 构造函数
- ✨2.2 析构函数
- ✨2.3 赋值操作符
- ✨2.4 关键成员函数
- 🎄3. 使用指南
- ✨3.1 适用场景
- ✨3.2 基本用法
- ✨3.3 注意事项
- ✨3.4 自定义删除器
- 🎄4. 实现原理
- ✨4.1 控制块(Control Block)
- ✨4.2 生命周期管理
- ✨4.3 内存布局
- 🎄5. 常见问题与最佳实践
- ✨5.1 常见陷阱
- ✨5.2 最佳实践
- 🎄结语
🎄一、概述
std::weak_ptr
是 C++11 引入的智能指针,用于解决 shared_ptr
的 循环引用问题 和实现 非拥有观察者模式。它不直接管理对象的生命周期,而是通过观察 shared_ptr
的引用计数,提供一种安全的方式访问被 shared_ptr
管理的对象。
核心特性:
-
不增加引用计数:不会影响
shared_ptr
管理的对象的生命周期。 -
观察者角色:可检测对象是否已被释放(避免悬空指针)。
-
需转换为
shared_ptr
:必须通过 lock() 获取临时所有权才能访问对象。
🎄二、核心成员函数详解
✨2.1 构造函数
构造函数 | 描述 | 示例 |
---|---|---|
默认构造 | 创建空的 weak_ptr | weak_ptr<int> wp; |
从 shared_ptr 构造 | 观察 shared_ptr 管理的对象 | shared_ptr<int> sp(new int(42)); weak_ptr<int> wp(sp); |
拷贝构造 | 拷贝另一个 weak_ptr 的观察状态 | weak_ptr<int> wp2(wp1); |
移动构造 | 转移观察状态,原 weak_ptr 置空 | weak_ptr<int> wp3(std::move(wp2)); |
✨2.2 析构函数
- 不影响
shared_ptr
的引用计数,仅释放观察状态。
✨2.3 赋值操作符
weak_ptr& operator=(const weak_ptr& r); // 拷贝赋值
weak_ptr& operator=(weak_ptr&& r); // 移动赋值
weak_ptr& operator=(const shared_ptr<T>& r); // 从 shared_ptr 赋值
✨2.4 关键成员函数
函数 | 描述 | 示例 |
---|---|---|
lock() | 返回一个 shared_ptr ,若对象存活则共享所有权;否则返回空 | shared_ptr<int> sp = wp.lock(); |
expired() | 检查被观察对象是否已被释放(等价于 use_count() == 0 ) | if (wp.expired()) { ... } |
use_count() | 返回关联的 shared_ptr 的引用计数 | long count = wp.use_count(); |
reset() | 解除观察,置空 weak_ptr | wp.reset(); |
swap() | 交换两个 weak_ptr 的观察状态 | wp1.swap(wp2); |
🎄3. 使用指南
✨3.1 适用场景
- 打破循环引用:
class B; class A { shared_ptr<B> b_ptr; }; class B { weak_ptr<A> a_ptr; // 避免循环引用 };
- 观察者模式:
允许临时访问对象,但不影响其生命周期(如缓存、事件监听)。 - 缓存管理:
缓存对象时使用weak_ptr
,当对象未被其他shared_ptr
引用时自动释放。
✨3.2 基本用法
shared_ptr<int> sp = make_shared<int>(42);
weak_ptr<int> wp(sp); // 访问对象前必须调用 lock()
if (shared_ptr<int> tmp = wp.lock()) { cout << *tmp << endl; // 对象存活
} else { cout << "对象已释放" << endl;
}
✨3.3 注意事项
- 不可直接解引用:
weak_ptr
没有operator*
或operator->
,必须通过lock()
获取shared_ptr
。 - 线程安全性:
lock()
和expired()
在多线程环境下需同步(即使引用计数原子增减,对象可能被其他线程释放)。 - 性能开销:
lock()
操作会涉及引用计数检查,高频调用需谨慎。
✨3.4 自定义删除器
weak_ptr
不直接支持自定义删除器,但继承自关联的shared_ptr
。- 若
shared_ptr
使用了自定义删除器,通过lock()
获取的shared_ptr
也会保留该删除器。
🎄4. 实现原理
✨4.1 控制块(Control Block)
weak_ptr
与关联的shared_ptr
共享控制块,控制块包含:- 强引用计数(use_count):由
shared_ptr
管理。 - 弱引用计数(weak_count):由
weak_ptr
管理。 - 其他信息(如删除器、分配器等)。
- 强引用计数(use_count):由
✨4.2 生命周期管理
-
对象释放条件:
- 当
use_count
归零时,对象被销毁(调用删除器),但控制块仍存在。 - 控制块在
weak_count
也归零时 才会被释放。
- 当
-
lock()
的内部逻辑:shared_ptr<T> lock() const { if (expired()) return nullptr; return shared_ptr<T>(*this); // 通过 weak_ptr 构造 shared_ptr }
- 若对象存活,构造
shared_ptr
会增加use_count
。
- 若对象存活,构造
✨4.3 内存布局
make_shared
优化:对象与控制块分配在连续内存中。- 独立分配:直接构造
shared_ptr
时,对象与控制块分离。
🎄5. 常见问题与最佳实践
✨5.1 常见陷阱
-
误用
expired()
+lock()
:
多线程环境下,expired()
检查后对象可能被释放,导致lock()
返回空。if (!wp.expired()) { // 此处对象可能已被其他线程释放 shared_ptr<T> sp = wp.lock(); // 可能得到空指针 }
正确做法:直接调用
lock()
并检查结果。 -
保留无用的
weak_ptr
:
长期持有weak_ptr
会导致控制块无法释放,增加内存占用。
✨5.2 最佳实践
- 优先使用
lock()
:避免单独依赖expired()
。 - 及时
reset()
:不再需要观察时主动释放weak_ptr
。 - 结合
make_shared
:减少内存碎片,提升性能。 - 避免跨线程传递裸
weak_ptr
:传递shared_ptr
或封装访问逻辑。
🎄结语
std::weak_ptr
是 C++ 智能指针体系中的重要补充,通过非拥有观察者的角色,有效解决了 shared_ptr
的循环引用问题,并支持灵活的缓存和观察者模式设计。理解其成员函数、实现原理及适用场景,能帮助开发者在复杂资源管理场景中编写更安全、高效的代码。始终遵循“检查-访问”模式(通过 lock()
),并注意线程安全和生命周期管理,是使用 weak_ptr
的关键。
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁
参考:
C++ 智能指针详解:std::unique_ptr、std::shared_ptr 和 std::weak_ptr
https://cplusplus.com/reference/memory/shared_ptr/