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

c++如何实现观察者模式_c++ 事件委托与通知机制设计【案例】

冬宇大大_7243

冬宇大大_7243

发布时间:2025-12-27 14:47:34

|

825人浏览过

|

来源于php中文网

原创

std::function + std::vector 足以实现轻量、类型安全、无内存泄漏的观察者模式,无需GoF类图;核心是支持注册、调用与解绑,配合 weak_ptr 和 erase_if 可安全处理生命周期与中途移除问题。

c++如何实现观察者模式_c++ 事件委托与通知机制设计【案例】

为什么 std::function + std::vector 就够用了

观察者模式在 C++ 里不必强行套用经典 GoF 类图。现代 C++ 的 std::function 和 std::vector 足以支撑轻量、类型安全、无内存泄漏的通知机制,且避免虚函数开销和继承耦合。

关键不是“实现模式”,而是“让通知可注册、可调用、可解绑”。下面所有设计都围绕这个目标展开:

  • std::function<void></void> 封装任意可调用体(lambda、成员函数指针、普通函数),类型擦除但编译期检查参数匹配
  • 用 std::vector 存储观察者,简单直接;若需频繁增删查,可换 std::unordered_map 配唯一 ID,但多数场景没必要
  • 不依赖基类或接口,观察者无需继承、无需实现特定函数,降低侵入性

如何安全绑定成员函数并避免悬空调用

成员函数指针必须绑定对象实例,而对象生命周期常早于事件源。最常见错误是捕获局部对象或已析构对象的 this 指针,导致未定义行为。

推荐做法:统一用 std::shared_ptr 管理被观察对象,并要求观察者也通过 std::weak_ptr 持有引用 —— 这样既支持自动解绑,又不延长对象寿命:

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

class Subject {
public:
    using Callback = std::function<void(int)>;
    void attach(Callback cb) { observers_.push_back(cb); }
    void notify(int value) {
        for (auto& cb : observers_) cb(value);
    }
<p>private:
std::vector<Callback> observers_;
};</p><p>struct Observer {
explicit Observer(std::shared<em>ptr<Subject> sub)
: subject</em>(sub) {
// 绑定时捕获 weak<em>ptr,调用前 lock()
subject</em>->attach([wp = std::weak_ptr<Observer>(shared_from_this())](int v) {
if (auto self = wp.lock()) {
self->onEvent(v);
}
});
}
void onEvent(int v) { /<em> ... </em>/ }
std::shared_ptr<Observer> shared_from_this() { return shared_from_this(); }
std::shared<em>ptr<Subject> subject</em>;
};</p>

std::erase_if + std::shared_ptr 解决通知中途移除观察者的问题

通知过程中,某个回调可能调用 detach(),直接 erase 迭代器会破坏循环。传统方案用两遍遍历(标记+清理)或手动维护索引,繁琐易错。

C++ 算法竞赛自动化测试数据生成与校验框架
C++ 算法竞赛自动化测试数据生成与校验框架

根据原题生成新题面、验证器及完整测试数据,自动套用 testlib 模板,用于用户要求生成测试数据时。

下载

C++20 起,std::erase_if 是更干净的解法:先收集待移除项,再批量擦除。配合 std::shared_ptr 的引用计数,还能自然处理“通知中 self-destruct”场景:

  • 在 notify() 前复制一份 observers_,确保迭代安全
  • 每个回调内部若调用 detach(),只标记自身失效,不立即修改原容器
  • 通知结束后,用 std::erase_if(observers_, [](auto& cb) { return cb.expired(); }) 清理(若用 std::weak_ptr 包裹回调)

若不用弱引用,也可用 token 机制:每次 attach() 返回一个 std::size_t id,detach(id) 标记该 id 失效,notify() 跳过失效项。

事件委托与跨线程通知的边界在哪

纯内存内通知(同一线程)不需要锁或队列。一旦涉及多线程,就不再是“观察者模式”的范畴,而是“事件总线”或“消息泵”的职责。

常见误用:在 UI 线程注册回调,却从后台线程触发 notify(),导致 GUI 操作崩溃。此时必须明确约定:

  • 事件源不负责线程调度 —— 由使用者决定是否投递到主线程(如 Qt 的 QMetaObject::invokeMethod,或 Windows 的 PostMessage)
  • 若需异步通知,应显式封装为 std::thread 或 std::async,并在回调内做线程安全判断(例如检查 QThread::currentThread() == ui_thread_)
  • 不要在 std::function 容器里存裸函数指针 + void* 用户数据 —— 这种 C 风格写法丢失类型信息,且无法自动管理生命周期

真正难的从来不是怎么发通知,而是谁来保证“发出去之后,接收方还活着、还在正确线程、还没被用户关掉窗口”。这部分逻辑必须外提,不能塞进 Subject 类里。

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
WorkBuddy

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

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

立刻MV
立刻MV Hot

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

DeepSeek

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

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

豆包大模型

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

Loomy
Loomy Hot

一款AI工具,主要用于科大讯飞发布的桌面级 AI 助理,比 OpenClaw 更易用、更安全!,适合需要提升相关任务效率的用户。

超级简历WonderCV

一款AI办公效率工具,主要用于免费求职简历模版下载制作,应届生职场人必备简历制作神器,适合需要提升相关任务效率的用户。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

相关专题

更多
C++ Qt图形开发
C++ Qt图形开发

本专题专注于 C++ Qt框架在图形界面开发中的应用,系统讲解窗口设计、信号与槽机制、界面布局、事件处理、数据库连接与跨平台打包等核心技能,通过多个桌面应用项目实战,帮助学员快速掌握 Qt 框架并独立完成跨平台GUI软件的开发。

3822

2025.08.15

C++桌面程序开发
C++桌面程序开发

本专题聚焦 C++ 在桌面端图形界面应用开发中的实战应用,系统讲解 Qt 框架的信号与槽机制、界面布局管理、事件响应、数据交互、样式美化与多窗口应用设计等核心知识。通过实战案例(如记事本应用、数据管理工具、系统监控面板),帮助学习者掌握 从UI设计到完整桌面软件开发的C++工程化能力。

1154

2025.10.23

C++ 图形界面开发基础(Qt方向)
C++ 图形界面开发基础(Qt方向)

本专题系统讲解 使用 C++ 与 Qt 进行图形界面(GUI)开发的核心技能,内容涵盖 Qt 项目结构、窗口组件、信号与槽机制、事件处理、布局管理、资源管理,以及跨平台编译与打包流程。通过多个小型桌面应用实战案例,帮助学习者掌握从界面设计到功能实现的完整 GUI 开发能力。

1401

2025.12.05

登录token无效
登录token无效

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

12186

2023.09.14

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

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

1485

2023.09.14

token怎么获取
token怎么获取

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

3257

2023.12.21

token什么意思
token什么意思

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

5421

2024.03.01

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

616

2023.11.23

Buffalo框架数据库开发全教程
Buffalo框架数据库开发全教程

本专题围绕Buffalo框架数据库开发,讲解database.yml多环境配置、soda与fizz迁移生成回滚、模型结构体标签、增删改查与条件查询、一对多与多对多关联、数据校验、回调钩子、事务处理及原生SQL执行能力。

160

2026.09.23

热门下载

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

精品课程

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

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