欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > 【C++ | 内存管理】C++ weak_ptr 详解:成员函数、使用例子与实现原理

【C++ | 内存管理】C++ weak_ptr 详解:成员函数、使用例子与实现原理

2025/5/18 2:54:20 来源:https://blog.csdn.net/wkd_007/article/details/147991267  浏览:    关键词:【C++ | 内存管理】C++ weak_ptr 详解:成员函数、使用例子与实现原理

😁博客主页😁:🚀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_ptrweak_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() == 0if (wp.expired()) { ... }
use_count()返回关联的 shared_ptr 的引用计数long count = wp.use_count();
reset()解除观察,置空 weak_ptrwp.reset();
swap()交换两个 weak_ptr 的观察状态wp1.swap(wp2);

在这里插入图片描述

🎄3. 使用指南

✨3.1 适用场景

  1. 打破循环引用:
    class B;  
    class A {  shared_ptr<B> b_ptr;  
    };  
    class B {  weak_ptr<A> a_ptr;  // 避免循环引用  
    };  
    
  2. 观察者模式
    允许临时访问对象,但不影响其生命周期(如缓存、事件监听)。
  3. 缓存管理
    缓存对象时使用 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 管理。
    • 其他信息(如删除器、分配器等)。

✨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 最佳实践

  1. 优先使用 lock():避免单独依赖 expired()
  2. 及时 reset():不再需要观察时主动释放 weak_ptr
  3. 结合 make_shared:减少内存碎片,提升性能。
  4. 避免跨线程传递裸 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/

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词