0

0

C++中std::weak_ptr如何判断它指向的对象是否已被析构? (expired方法)

尼克

尼克

发布时间:2026-02-13 13:36:11

|

274人浏览过

|

来源于php中文网

原创

expired()仅检查控制块是否存活,返回false不保证对象未析构,安全访问必须依赖lock()成功获取非空shared_ptr。

c++中std::weak_ptr如何判断它指向的对象是否已被析构? (expired方法)

std::weak_ptr::expired() 是最直接的判断方式

它专为这个目的设计,比 lock() 后判空更轻量——不构造 shared_ptr,只查控制块里的引用计数是否归零。内部通常就是原子读一次弱引用计数,没锁开销。

常见错误是以为 expired() 返回 false 就代表对象“一定还活着且能安全访问”,其实不是:它只说明控制块还在,但对象可能刚被析构、还没清理控制块(比如析构函数里还有异步任务在用 weak_ptr)。所以 expired() == false 只是必要不充分条件。

  • expired() 返回 true → 对象肯定已析构,控制块也释放了,绝对不能调用 lock()
  • expired() 返回 false → 控制块尚存,但对象可能正处在析构中途;必须紧接着用 lock() 获取 shared_ptr 才能确认能否访问
  • 不要用 use_count() == 0 替代 expired(),因为弱引用存在时 use_count() 可能为 0 但控制块未销毁

lock() 成功才是安全访问对象的唯一依据

lock() 不仅检查对象状态,还会尝试原子地将弱引用升级为强引用。只有它返回非空 shared_ptr,才真正保证:对象尚未析构 + 当前线程可安全访问。

典型误用是先 if (!wp.expired()) { auto sp = wp.lock(); /* 然后用 sp */ } —— 这中间有竞态窗口:expired() 返回 false 后、lock() 执行前,对象可能已被析构。正确写法是跳过 expired(),直接 auto sp = wp.lock(); if (sp) { /* 用 sp */ }

简篇AI排版
简篇AI排版

AI排版工具,上传图文素材,秒出专业效果!

下载

立即学习C++免费学习笔记(深入)”;

  • 每次需要访问对象时,都应独立调用 lock(),别缓存结果(除非你明确知道生命周期)
  • lock() 失败返回空 shared_ptr,不是异常,不用 try/catch
  • 在回调、定时器、线程池等异步场景中,这是唯一靠谱的存活检查手段

为什么不能靠 try-catch 捕获访问崩溃?

C++ 中通过已析构对象的指针访问内存,属于未定义行为(UB),不是 C++ 异常。不会抛出 std::bad_weak_ptr 或其他异常——那玩意儿只在 weak_ptr 本身未初始化或被 move 走后调用 lock() 才抛。对象析构后访问,大概率直接 segfault 或静默错乱,catch 不到。

  • std::bad_weak_ptr 的触发条件是:weak_ptr 构造自空 shared_ptr,或已被 move,或从未赋值
  • 对象析构 ≠ weak_ptr 变成“坏的”,它依然合法,只是 lock() 返回空
  • 依赖信号处理(如 SIGSEGV)捕获这种错误,在多线程下不可靠且难以调试

一个容易被忽略的细节:自析构对象中的 weak_ptr

如果对象在自己的成员函数里调用 shared_from_this() 得到 shared_ptr,再转成 weak_ptr,然后又在析构函数里去 lock() —— 这时候 lock() 一定失败,但 expired() 可能还返回 false。因为控制块销毁晚于对象析构,而析构函数执行期间控制块仍存在。

这意味着:在对象内部持有自身 weak_ptr 并试图“观察自己是否将死”,逻辑上就不可靠。这种模式本身就有问题,应避免。

  • 自管理生命周期时,优先用 shared_from_this() + 显式 reset(),而非依赖 weak_ptr 回查
  • 若必须用 weak_ptr 做延迟清理,确保所有 lock() 调用都在对象外部上下文中
  • 控制块销毁时机由最后一个 shared_ptr 和最后一个 weak_ptr 共同决定,不是对象析构那一刻

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

807

2023.08.22

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

673

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

325

2025.12.24

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

24

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

24

2026.01.21

C# 多线程与异步编程
C# 多线程与异步编程

本专题深入讲解 C# 中多线程与异步编程的核心概念与实战技巧,包括线程池管理、Task 类的使用、async/await 异步编程模式、并发控制与线程同步、死锁与竞态条件的解决方案。通过实际项目,帮助开发者掌握 如何在 C# 中构建高并发、低延迟的异步系统,提升应用性能和响应速度。

91

2026.02.06

pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

12

2026.02.13

微博网页版主页入口与登录指南_官方网页端快速访问方法
微博网页版主页入口与登录指南_官方网页端快速访问方法

本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。

9

2026.02.13

Flutter跨平台开发与状态管理实战
Flutter跨平台开发与状态管理实战

本专题围绕Flutter框架展开,系统讲解跨平台UI构建原理与状态管理方案。内容涵盖Widget生命周期、路由管理、Provider与Bloc状态管理模式、网络请求封装及性能优化技巧。通过实战项目演示,帮助开发者构建流畅、可维护的跨平台移动应用。

7

2026.02.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 9.3万人学习

C 教程
C 教程

共75课时 | 4.7万人学习

C++教程
C++教程

共115课时 | 17.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号