C++ 实现轻量级观察者模式(RAII 风格封装)回调管理逻辑方案源码【源码】

千辰吖_5761

千辰吖_5761

2026-05-21

870人浏览

原创

直接用 std::function + std::vector 注册回调易导致野指针崩溃,因生命周期完全依赖使用者;raii 应通过 observerhandle(移动安全、析构自动解绑)绑定回调与观察者生存期,避免 shared_ptr/weak_ptr 开销。

c++ 实现轻量级观察者模式(raii 风格封装)回调管理逻辑方案源码【源码】

为什么直接用 std::function + std::vector 注册回调容易出问题

因为生命周期管理完全甩给使用者:观察者对象销毁了,但回调还留在被观察者里,下次触发就 std::bad_function_call 或野指针崩溃。RAII 的核心不是“自动释放”,而是“绑定生存期”——让回调的存续明确依附于某个对象的生命周期。

常见错误现象:Segmentation fault 出现在第 3 次通知后;调试发现 std::function 内部保存的是已析构对象的 this 指针;weak_ptr 方案又引入虚表和引用计数开销,不轻量。

  • 避免裸指针或 shared_ptr 持有观察者:破坏 RAII 的确定性析构
  • 拒绝在被观察者中维护“弱引用池”:增加复杂度且仍需手动清理
  • 关键思路:把“注册”动作变成一个拥有析构行为的对象(即句柄),由它负责反注册

ObserverHandle 必须支持移动、不可复制、析构即解绑

这是 RAII 封装成败的关键。句柄本身不持有业务逻辑,只记下被观察者的注销接口(函数指针或 lambda)和唯一 ID(用于快速查找)。它的析构必须无条件触发一次解绑。

示例结构简写:

class ObserverHandle {
    std::function<void> m_unsubscribe;
public:
    explicit ObserverHandle(std::function<void> unsub) 
        : m_unsubscribe(std::move(unsub)) {}
    ObserverHandle(ObserverHandle&&) noexcept = default;
    ObserverHandle(const ObserverHandle&) = delete;
    ObserverHandle& operator=(const ObserverHandle&) = delete;
    ObserverHandle& operator=(ObserverHandle&&) noexcept = default;
    ~ObserverHandle() { if (m_unsubscribe) m_unsubscribe(); }
};</void></void>

注意:m_unsubscribe 必须是可调用对象,不能是 raw function pointer(无法捕获上下文),也不能是带状态的 std::function 以外的类型(兼容性差)。

  • 移动构造/赋值必须 noexcept,否则容器操作(如 std::vector::push_back)可能异常中止导致泄漏
  • 析构中判空再调用,防止多次移动后重复解绑
  • 不要在句柄里存 this 或观察者引用——那是使用者的责任

被观察者端用 std::vector<:function>></:function> 最简可行,但要注意迭代器失效

不需要哈希表或红黑树——轻量级场景下,顺序遍历 + 索引擦除足够快;且避免引入额外内存分配和比较开销。问题在于:通知过程中若某回调触发自身解绑,erase 会让后续迭代器失效。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载

解决方式不是锁或延迟删除,而是“反向遍历 + 下标访问”:

for (size_t i = m_callbacks.size(); i > 0; --i) {
    if (m_callbacks[i-1]) {  // 防空回调
        m_callbacks[i-1]();
    }
}

这样即使中间某次调用导致 m_callbacks 缩容,也不会影响前面的索引。

  • 回调存储用 std::vector<:function>></:function>,不用 std::list:后者每次插入都 new,违背“轻量”目标
  • 注册返回 ObserverHandle,内部 unsubscribe lambda 捕获 this 和当前索引(或迭代器),执行 erase 即可
  • 不提供“按名称/类型解绑”接口:增加泛型复杂度,且违背“句柄即生命周期”的设计契约

使用时最容易忽略:lambda 捕获方式决定是否安全

你写的这个 lambda,是不是用了 [this]?如果 this 指向栈对象或即将析构的对象,句柄还在,回调一触发就崩。RAII 只管“谁来解绑”,不管“绑的是什么”。

正确姿势只有两种:

  • 观察者是堆对象(new 或 std::make_unique),且保证生命周期长于被观察者 → 用 [this]
  • 观察者是栈对象,必须用 [&local_var] 捕获局部变量,或更推荐:把回调逻辑封装进成员函数,再用 [this] 绑定该函数(前提是 this 安全)

典型翻车代码:auto h = subject.observe([this]{ onEvent(); }); —— 若 this 是临时作用域里的对象,这行之后句柄就已悬空。

真正轻量的核心,是把生命周期责任推回给使用者,而不是在框架层加一堆运行时检查或智能指针开销。一旦接受这个前提,实现就非常干净。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关专题

更多
c++和c语言的区别有哪些
c++和c语言的区别有哪些

c++和c语言的区别:1、面向对象编程(OOP)支持不同;2、新增特性不同;3、标准库不同;4、编译方式不同;5、命名空间不同等等。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.14

2248

9

c++和python学习顺序推荐
c++和python学习顺序推荐

一般建议先学习C++,再学习Python,因为这样可以逐步从较为底层的编程语言向更高级的语言过渡。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

1019

6

python和c++学习性价比分析
python和c++学习性价比分析

Python易于学习,广泛应用于Web开发、数据科学和人工智能等领域,但性能较低。C语言性能高,适用于对性能要求较高的场景,如游戏开发和系统编程,但学习曲线陡峭,错误处理复杂。想了解更多python的相关内容,可以阅读本专题下面的文章。

2024.03.14

447

5

c语言和c++一样吗
c语言和c++一样吗

c语言和c++是两种不同的编程语言,虽然有相似之处,但存在显著差异。c语言专注于过程式编程和系统级开发,以简洁、高效著称。c++作为c语言的超集,引入了面向对象编程,增强了代码组织和管理能力,但学习曲线也更陡峭。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

327

5

c语言和c++先学哪个好
c语言和c++先学哪个好

初学者选择学习c语言还是c++语言,需要根据个人学习目标、背景以及编程兴趣和预期应用方向来决定。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

406

5

c语言和c++的区别和联系
c语言和c++的区别和联系

c语言和c++是计算机科学领域应用广泛的编程语言。虽然它们有着相似的基础,但它们在语言类型、语法功能和内存管理方面存在着显著差异。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.14

580

5

c++软件中文更改教程
c++软件中文更改教程

对于 ide,可通过打开设置,找到语言设置,选择中文,并保存更改。对于非 ide 应用程序,可查找设置或选项,选择语言设置,更改为中文,并保存更改。想了解更多c++的相关内容,可以阅读本专题下面的文章。

2024.03.21

1409

9

python和java和c++学习性价比分析
python和java和c++学习性价比分析

Python以其易学性、丰富的库和活跃的社区而著称,适合数据科学、人工智能和Web开发。Java以其跨平台性、企业级应用开发和Android应用开发而闻名。C++以其底层控制能力、高效性能和游戏开发而著称。选择哪种语言取决于个人兴趣、职业方向和特定需求。想了解更多python和java和c++的相关内容,可以阅读本专题下面的文章。

2024.03.22

1217

7

c++和c语言学习顺序推荐
c++和c语言学习顺序推荐

对于初学者,建议先学习C语言,掌握编程基础后再转入C++,便于理解面向对象编程概念。有编程经验者可直接学习C++,快速接触高级编程技术。想了解更多c++和c语言的相关内容,可以阅读本专题下面的文章。

2024.03.25

1325

9

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程