讲师中心 微信公众号
AI工具推荐 视频效率加速

C++如何实现观察者模式?(事件回调机制示例)

冬萱姑娘_6646

冬萱姑娘_6646

发布时间:2026-02-22 10:09:11

|

549人浏览过

|

来源于php中文网

原创

C++观察者模式推荐用std::vector存储回调,避免裸指针和shared_ptr基类;注册时谨慎捕获变量,通知时浅拷贝容器防迭代器失效;提供sync/async双接口,异步需复制回调;手写比signal/slot库更轻量可控。

c++如何实现观察者模式?(事件回调机制示例)

std::function + std::vector 怎么存回调函数

观察者模式的核心是“一堆对象等着被通知”,C++里最轻量、最可控的做法就是用 std::vector 存 std::function。别碰裸指针或 std::shared_ptr 包装的抽象基类——除非你真需要运行时多态解耦,否则纯属增加生命周期管理负担。

常见错误是把 std::function 当成普通函数指针用,结果捕获了局部变量却没检查生命周期:[&] 在异步通知中大概率导致崩溃;[=] 捕获值又容易忽略对象是否可拷贝。

  • 只捕获必要项,优先用 [this] 或 [ptr = shared_from_this()](如果用了 std::enable_shared_from_this)
  • 注册回调时,建议用返回值标识订阅句柄(比如 size_t 索引或 int64_t token),方便后续移除
  • 避免在回调执行中途修改容器——std::vector 的 erase 会失效迭代器,通知循环得用下标或先收集待删索引

notify() 里怎么安全遍历并调用观察者

最典型的坑是:一边通知一边有观察者自己调用 unsubscribe(),导致迭代器失效或访问野指针。C++ 没有内置“快照式遍历”,得手动处理。

不是所有场景都需要深拷贝回调列表——如果通知是同步的、且明确禁止在回调里改订阅关系,那直接遍历原容器就行;但只要有一丁点可能(比如日志观察者写磁盘慢、触发重试逻辑),就必须隔离。

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

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载
  • 推荐做法:进入 notify() 后,用 auto observers = m_observers; 浅拷贝一份 std::vector<:function>></:function>,再遍历它
  • 浅拷贝开销小(std::function 内部是小对象优化+指针),比锁 + 迭代器安全方案更简单可靠
  • 如果观察者数量极大(比如上万)、且通知极频繁,才考虑用 std::shared_ptr<const std::vector>></const> 配合原子指针交换,但绝大多数业务用不到

如何支持跨线程通知(不崩、不丢、不卡)

观察者模式默认是同步调用,一旦某个回调阻塞或抛异常,整个通知链就停住。跨线程不是加个 std::thread 就行——核心矛盾是:谁负责生命周期?谁处理异常?消息顺序还保不保?

别用全局队列+单消费者线程来“统一派发”,这会让调用栈不可控、调试困难。真正合理的做法是让事件发布者决定分发策略。

  • 提供两个通知接口:notify_sync()(当前线程立即调用)和 notify_async()(用 std::async(std::launch::async, ...) 或线程池投递)
  • notify_async() 内部必须复制回调对象(即再次浅拷贝),因为原始 m_observers 可能被其他线程修改
  • 异步回调里别 throw 异常——std::async 不传播异常到发布者,得用 std::future::wait() 主动取,但通常没人这么干;更实际的是记录日志 + 继续下一个

为什么不用 signal/slot 库(如 libsigc++、Boost.Signals2)

这些库确实封装了连接管理、自动断连、线程安全等,但代价是:二进制体积增大、编译时间变长、调用栈更深、部分实现依赖 RTTI 或异常。一个只有几十行的 Subject 类,往往比引入整个 Boost 更可靠。

它们真正的适用场景是:项目已重度使用该生态、需要信号合并/限流/延迟触发等高级特性,或者团队对自研机制缺乏信心。但如果你只是想让 UI 控件响应数据变化,或模块间松耦合通信,手写更透明、更容易 debug。

  • Boost.Signals2 的 scoped_connection 看似优雅,但若观察者对象析构顺序不对,仍可能调用已释放内存
  • libsigc++ 的模板深度高,错误信息极其晦涩,比如 sigc::slot 类型不匹配时,编译器报错常跨越百行
  • 手写方案里,每个 unsubscribe() 就是简单的 vector.erase(),哪行崩了一眼就能定位

复杂点永远在生命周期管理——不是语法难,而是你得清楚谁 new 谁 delete、谁 hold 引用、谁负责在析构前清理订阅。这点,任何库都不会替你做决定。

热门AI工具

更多
豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

讯飞智文

一款面向学习和办公场景的AI文档创作工具,可辅助生成PPT与Word文档,提高资料整理和内容制作效率。

Flowith
Flowith Hot

Flowith是一款基于画布和智能体工作流的 AI 协作工作空间。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

相关专题

更多
java多态详细介绍
java多态详细介绍

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

375

2025.11.27

登录token无效
登录token无效

登录token无效解决方法:1、检查token的有效期限,如果token已经过期,需要重新获取一个新的token;2、检查token的签名,如果签名不正确,需要重新获取一个新的token;3、检查密钥的正确性,如果密钥不正确,需要重新获取一个新的token;4、使用HTTPS协议传输token,建议使用HTTPS协议进行传输 ;5、使用双因素认证,双因素认证可以提高账户的安全性。

15026

2023.09.14

登录token无效怎么办
登录token无效怎么办

登录token无效的解决办法有检查Token是否过期、检查Token是否正确、检查Token是否被篡改、检查Token是否与用户匹配、清除缓存或Cookie、检查网络连接和服务器状态、重新登录或请求新的Token、联系技术支持或开发人员等。本专题为大家提供token相关的文章、下载、课程内容,供大家免费下载体验。

1765

2023.09.14

token怎么获取
token怎么获取

获取token值的方法:1、小程序调用“wx.login()”获取 临时登录凭证code,并回传到开发者服务器;2、开发者服务器以code换取,用户唯一标识openid和会话密钥“session_key”。想了解更详细的内容,可以阅读本专题下面的文章。

4197

2023.12.21

token什么意思
token什么意思

token是一种用于表示用户权限、记录交易信息、支付虚拟货币的数字货币。可以用来在特定的网络上进行交易,用来购买或出售特定的虚拟货币,也可以用来支付特定的服务费用。想了解更多token什么意思的相关内容可以访问本专题下面的文章。

6361

2024.03.01

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

2398

2023.09.20

C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

379

2026.04.23

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

3228

2023.10.19

Postman身份认证怎么配置
Postman身份认证怎么配置

本专题从实际API接口调试场景出发,讲解Postman身份认证的完整配置流程,包括常见认证协议介绍、授权参数设置、访问令牌填写、OAuth 2.0授权及认证失败排查,帮助用户正确完成接口授权与访问验证。

0

2026.11.06

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn