C++中如何实现简单的观察者模式_C++解耦组件间通信方法【设计】

2次阅读

用std::function+std::vector可轻量实现观察者模式,核心是存储回调并遍历通知;需规避悬空指针、迭代器失效及自我注销问题,推荐结合weak_ptr/shared_ptr管理生命周期,比虚函数继承更灵活高效。

C++中如何实现简单的观察者模式_C++解耦组件间通信方法【设计】

std::function + std::vector 实现轻量观察者注册表

不需要引入第三方库或复杂基类,c++11 起就能靠标准库搭出可用的观察者模式。核心是把回调抽象为 std::function(或带参数的变体),用 std::vector 存储,注册即 push_back,通知即遍历调用。

常见错误是直接存裸函数指针或 Lambda 捕获局部变量,导致调用时悬空。必须确保回调对象生命周期长于观察者容器,或用 std::shared_ptr 管理。

  • 推荐签名: using Callback = std::function;Event 是自定义结构体,比 void* 安全、比模板泛型更易维护
  • 注册时检查重复:可加 std::weak_ptr 配合 std::shared_ptr 实现自动去重与自动注销
  • 通知时避免迭代器失效:若回调内可能调用 unregister(),需先拷贝回调列表再遍历

如何安全处理观察者在回调中自我注销

这是最常踩的坑:遍历时删除容器元素,引发迭代器失效和未定义行为。不能边 for-range 边 erase。

正确做法是分离“通知”和“清理”。先收集待移除项,或改用索引遍历并倒序删,但更稳妥的是两阶段策略:

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

  • 第一阶段:遍历原始 std::vector<:weak_ptr>>,调用 lock() 获取有效回调,存入临时 std::vector<:function>>
  • 第二阶段:遍历临时列表执行调用;结束后再扫描原容器,erase 已过期的 weak_ptr
  • 如果不用智能指针,就要求调用方显式调用 unregister(),并在容器内部用 std::list 替代 std::vector,支持 O(1) 删除

为什么不用虚函数+继承实现?

纯虚基类(如 class Observer { virtual void onEvent(const Event&) = 0; };)看似经典,但在现代 C++ 中往往过度设计:

  • 每个具体观察者都要继承、实现虚函数,增加编译依赖和头文件耦合
  • 多态调用有虚表开销,虽小但对高频事件(如游戏帧更新)可测出差异
  • 无法直接绑定成员函数而不传对象指针,需额外包装(std::bind 或 lambda),反而不如 std::function 直观
  • 不支持无状态函数、静态函数、函数对象等灵活来源

除非你已有严格接口契约、需要运行时动态切换观察者类型,否则没必要上继承体系。

qtQObject::connect()标准库方案本质区别在哪

Qt 版本不是“更高级”,而是为特定场景深度优化:信号与槽自动管理对象生命周期(父对象析构时自动断连)、线程安全(跨线程队列投递)、元对象系统支持字符串名连接。这些都以宏、moc 编译器和运行时开销为代价。

标准库方案没这些——它也不该有。如果你的模块不涉及 GUI、不跨线程通信、不需要运行时反射,硬套 Qt 机制反而让逻辑变得隐晦且难测试。

真正要注意的是:Qt 的连接默认是 Qt::AutoConnection,跨线程时会排队,而手写方案默认是同步调用,想异步必须自己扔进 std::Threadstd::async,这点容易忽略。

text=ZqhQzanResources