C++怎么实现观察者模式_C++事件回调机制【响应】

1次阅读

观察者模式应使用std::function+std::vector存储回调,注册用Lambda或bind,notify时拷贝列表并try-catch隔离异常,用weak_ptr或observertoken管理生命周期,避免shared_ptr循环引用和遍历时删除。

C++怎么实现观察者模式_C++事件回调机制【响应】

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

观察者模式本质是“一函数等着被调用”,c++里最轻量、最灵活的载体就是 std::function<void></void>(或带参数的变体)。别用裸函数指针虚函数强制继承,那会绑死接口、增加耦合。

实操建议:

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

  • std::vector<:function Event>> m_observers</:function> 存回调,Event 是你定义的事件结构体,按需传参
  • 注册时直接用 lambda、成员函数绑定(std::bind[this]{...}),不用额外写观察者类
  • 注意:lambda 捕获局部变量时,确保被观察对象生命周期长于观察者;否则回调时访问野指针
  • 避免在回调里调用 remove_observer——遍历 vector 时删元素会崩,改用“标记+延迟清理”或 erase-remove 惯用法

notify() 里怎么安全触发所有回调

常见错误是边遍历边修改容器,或者没处理回调抛异常导致整个通知链中断。C++没内置“异常隔离”,得自己兜底。

实操建议:

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

  • 先拷贝一份 observer 列表:auto observers = m_observers,再遍历它,这样增删不影响当前通知
  • 每个回调外层套 try { ... } catch (...) { /* 记日志,不 throw */ },防止一个挂掉全军覆没
  • 不要在 notify 里锁全局 mutex——如果回调本身又去等其他锁,极易死锁;真要线程安全,用 std::shared_mutex 读多写少场景,或把同步逻辑交给调用方

怎么解耦观察者和被观察者的内存管理

裸指针、std::shared_ptr 都容易出问题:shared_ptr 循环引用,裸指针释放后还调用。核心矛盾是“谁负责告诉通知系统:我死了,别再叫我”。

实操建议:

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

  • std::weak_ptr 包裹观察者对象(比如 std::function<void></void>里捕获 weak_ptr,调用前 lock()
  • 更简单粗暴但实用的做法:观察者注册时返回一个 ObserverToken(本质是 size_t 索引或 void*),注销时传回来——由被观察者维护映射表,查表删对应项
  • 禁止让被观察者持有 shared_ptr<observer></observer>,这等于强迫观察者必须用 shared_ptr 构造,侵入性太强

std::signal/std::slot 库值不值得引入

boost::signals2qtQObject::connect 确实封装了自动断连、线程安全、序列化等,但代价是二进制体积、编译时间、学习成本。90% 的内部工具或游戏逻辑根本用不到那么重的功能。

实操建议:

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

  • 项目已用 Qt?直接用 QSignalMapper 或新式 connect,别重复造轮子
  • 纯 C++17 项目且需要跨线程自动队列?考虑 libsigc++ 或手写一个基于 std::queue + std::condition_variable异步分发器
  • 否则,坚持手写 50 行以内的 Subject 类——越简单,越容易定位回调不触发、重复注册、析构顺序错这类问题

真正难的不是写 notify,是搞清谁该在什么时候注销、回调里能不能 delete this、多线程下 event 对象该谁 delete。这些细节不画图、不跑 ASan,光看代码很难发现。

text=ZqhQzanResources