C++怎么使用观察者模式_C++事件处理教程【响应】

1次阅读

观察者模式在c++中需手动实现接口指针管理和生命周期控制;典型错误包括悬空指针和漏通知,推荐用std::weak_ptr存储观察者并及时清理。

C++怎么使用观察者模式_C++事件处理教程【响应】

观察者模式在 C++ 里不是靠语言特性,而是靠接口 + 指针/引用 + 容器手动搭

它没有 Event 关键字,也不像 C# 那样有 += 语法糖。你得自己定义通知接口、维护观察者列表、处理生命周期——否则很容易崩溃或漏通知。

典型错误现象:Segmentation fault(观察者已析构但还在列表里)、notify() 调用后行为没反应(忘了调 registerObserver()对象被提前释放)。

  • 观察者必须是对象或确保生命周期长于被观察者,对象注册后立即析构 = 悬空指针
  • 推荐用 std::weak_ptr<observer></observer> 存储观察者,避免循环引用;被观察者用 std::shared_ptr 管理自身时尤其关键
  • std::vector<:weak_ptr>></:weak_ptr> 是最常用容器,遍历时先 lock(),失败就 erase 对应项

怎么写一个最小可用的 Observer/Subject 接口

别一上来就抽象成模板类或支持泛型事件。先搞定「状态变更 → 通知所有活着的观察者」这个核心链路。

示例中 Subject 不持有具体业务逻辑,只管注册、移除、广播;Observer 只暴露虚函数 onStateChanged()

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

class Observer { public:     virtual ~Observer() = default;     virtual void onStateChanged(int newState) = 0; }; <p>class Subject { std::vector<std::weak<em>ptr<Observer>> observers</em>; public: void attach(std::shared<em>ptr<Observer> obs) { observers</em>.push<em>back(obs); } void notify(int state) { for (auto it = observers</em>.begin(); it != observers<em>.end();) { auto obs = it->lock(); if (obs) { obs->onStateChanged(state); ++it; } else { it = observers</em>.erase(it); // 自动清理失效项 } } } };</p>

std::function + Lambda 能替代 Observer 接口吗?能,但要小心捕获

可以,而且更轻量。但 lambda 捕获局部变量this 时极易产生悬空引用。

常见错误:在函数内注册一个捕获了局部 int x 的 lambda,函数返回后通知触发,访问已销毁的 x

  • 只捕获值([x]() { ... })或静态/全局对象是安全的
  • 捕获 this 必须确保被观察者生命周期严格长于 lambda 存活期;否则改用 std::weak_ptr<self></self> 在 lambda 内部 lock()
  • 存储 lambda 用 std::vector<:function>></:function>,但无法在运行时区分或移除特定回调 —— 所以需要额外 key 或用 map 管理

qt 的 signals/slots 算不算观察者模式?用的时候要注意什么

算,而且是高度封装的版本。但它依赖 QObject 继承和元对象系统,跟手写模式不是一回事。

容易踩的坑:connect() 默认是 Qt::AutoConnection,跨线程时若没显式指定 Qt::QueuedConnection,可能直接在发送线程调用槽函数,导致 ui 线程被阻塞或非 QObject 派生对象访问异常。

  • 信号参数类型必须完全匹配槽函数签名(C++11 后允许隐式转换,但不建议依赖)
  • 连接前检查 senderreceiver 是否为 nullptr,Qt5+ 不再自动判空
  • QObject::disconnect() 显式断开,或依赖父子关系自动清理;否则对象析构后信号仍可能触发已释放内存

多线程下清空观察者列表、跨线程发通知、lambda 捕获生命周期——这三个点,随便漏掉一个,程序就可能跑几天才崩,或者只在特定优化等级下出错。

text=ZqhQzanResources