c++轻量级观察者模式通过raii封装observerhandle实现自动注册/注销:构造时注册回调并保存weak_ptr,析构时查找并移除对应shared_ptr;subject用vector存shared_ptr,notify时lock调用,适用于≤100观察者场景。

在C++中实现轻量级观察者模式时,需确保观察者注册后能自动注销回调,避免悬空指针或重复析构——尤其当被观察对象生命周期短于观察者时,手动注销极易遗漏。
设计核心:RAII封装观察者句柄
定义一个 RAII 风格的 ObserverHandle 类,其构造时注册回调,析构时自动反注册。
第一步:声明被观察者基类接口,含 register_observer 与 unregister_observer 成员函数,返回类型为 ObserverHandle。
第二步:在被观察者内部维护一个 std::vector<:function>></:function> 或更安全的 std::vector<:weak_ptr>></:weak_ptr>(若用 shared_ptr 管理观察者);但此处采用更轻量方案——用 std::list<:function>>::iterator</:function> 存储每个观察者的注销句柄。
第三步:ObserverHandle 构造函数接收被观察者引用和一个 std::function<void></void> 回调,并立即调用被观察者的注册函数,获取对应注销迭代器;该迭代器被保存为私有成员;析构时,若迭代器有效,则调用被观察者的注销函数——【必须检查迭代器是否已失效,否则 erase 已 erase 过的迭代器将导致未定义行为】。
关键实现:注销逻辑的双重保障
方法一:使用 std::list::erase 后立即将迭代器置为 list.end(),并在 ObserverHandle 析构前判断是否等于 end()。
方法二:改用 std::vector 存储回调,但不直接存迭代器,而改用索引 + 布尔标志位数组;每次注销仅标记为失效,实际清理延迟到下一次通知前批量执行——这避免了 erase 迭代器失效问题,但增加通知开销。
方法三(推荐):在被观察者中维护 std::vector<:shared_ptr>>></:shared_ptr>,每个 ObserverHandle 持有一个 std::weak_ptr<:function>></:function>;析构时尝试 lock 并从 vector 中移除对应项;【vector 删除需线性查找,适合观察者数量 ≤100 的场景】。
完整可运行源码片段
定义被观察者类 Subject,含 notify() 和 register_observer();后者返回 ObserverHandle:
class Subject {
private:
std::vector<:shared_ptr>>> observers_;</:shared_ptr>
public:
auto register_observer(std::function<void> cb) -> ObserverHandle {</void>
auto sp = std::make_shared<:function>>(std::move(cb));</:function>
observers_.push_back(sp);
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
return ObserverHandle(*this, sp);
}
void notify() { for (auto& obs : observers_) if (auto p = obs.lock()) (*p)(); }
};
class ObserverHandle {
Subject& subj_;
std::weak_ptr<:function>> wp_;</:function>
public:
ObserverHandle(Subject& s, std::shared_ptr<:function>> sp) : subj_(s), wp_(sp) {}</:function>
~ObserverHandle() {
auto it = std::find_if(subj_.observers_.begin(), subj_.observers_.end(),
[this](const auto& ptr) { return ptr.get() == wp_.lock().get(); });
if (it != subj_.observers_.end()) subj_.observers_.erase(it);
}
};
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










