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

观察者模式在 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 后允许隐式转换,但不建议依赖)
- 连接前检查
sender和receiver是否为nullptr,Qt5+ 不再自动判空 - 用
QObject::disconnect()显式断开,或依赖父子关系自动清理;否则对象析构后信号仍可能触发已释放内存
多线程下清空观察者列表、跨线程发通知、lambda 捕获生命周期——这三个点,随便漏掉一个,程序就可能跑几天才崩,或者只在特定优化等级下出错。