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

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍 C++ 智能指针🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭
⏰发布时间⏰: 2025-05-16 12:19:44

本文未经允许,不得转发!!!


在这里插入图片描述

在这里插入图片描述

🎄一、概述

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/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wkd_007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值