导读:本期聚焦于小伙伴创作的《如何用C++结合RAII模式实现轻量级观察者模式的回调列表管理》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何用C++结合RAII模式实现轻量级观察者模式的回调列表管理》有用,将其分享出去将是对创作者最好的鼓励。

在C++开发中,观察者模式常用于处理事件通知逻辑,但手动管理观察者的注册和注销容易出现遗漏,导致悬空指针或者内存泄漏。结合RAII模式封装观察者模式,可以让观察者的生命周期和注册状态自动绑定,同时简化回调列表的管理逻辑,实现轻量且安全的事件通知机制。

如何用C++结合RAII模式实现轻量级观察者模式的回调列表管理

核心设计思路

整个封装的核心分为两部分,一部分是Observer类,负责RAII管理观察者的注册与注销,另一部分是Subject类,负责维护回调列表和触发通知。观察者对象销毁时,会自动从主题的回调列表中移除自身,无需手动调用注销接口。

Observer类设计

Observer类持有主题的弱引用和自身的回调迭代器,构造时自动注册回调,析构时自动注销,避免手动操作带来的问题。

Subject类设计

Subject类内部维护一个回调列表,提供注册、注销、通知接口,注册时返回迭代器给Observer用于后续注销,通知时遍历回调列表执行所有注册的回调函数。

完整源码实现

以下是完整的实现代码,包含头文件和简单的测试示例:

#include <iostream>
#include <vector>
#include <functional>
#include <memory>
#include <algorithm>

// 前置声明Subject类
class Subject;

// 观察者类,RAII管理注册与注销
class Observer {
public:
    using Callback = std::function<void(int)>;
    using Iterator = std::vector<Callback>::iterator;

    // 构造时自动注册回调
    Observer(Subject* subject, Callback cb);
    // 析构时自动注销回调
    ~Observer();

    // 禁止拷贝,允许移动
    Observer(const Observer&) = delete;
    Observer& operator=(const Observer&) = delete;
    Observer(Observer&& other) noexcept;
    Observer& operator=(Observer&& other) noexcept;

private:
    Subject* subject_;  // 主题弱引用,不持有所有权
    Iterator it_;       // 回调在列表中的迭代器
    bool registered_;   // 标记是否已注册
};

// 主题类,管理回调列表和通知逻辑
class Subject {
public:
    using Callback = std::function<void(int)>;

    Subject() = default;
    ~Subject() = default;

    // 注册回调,返回迭代器用于注销
    std::vector<Callback>::iterator Register(Callback cb) {
        callbacks_.push_back(cb);
        return --callbacks_.end();
    }

    // 注销指定迭代器的回调
    void Unregister(std::vector<Callback>::iterator it) {
        callbacks_.erase(it);
    }

    // 触发通知,执行所有注册的回调
    void Notify(int value) {
        for (auto& cb : callbacks_) {
            if (cb) {
                cb(value);
            }
        }
    }

private:
    std::vector<Callback> callbacks_;  // 回调列表
    friend class Observer;
};

// Observer构造函数实现
Observer::Observer(Subject* subject, Callback cb) 
    : subject_(subject), registered_(true) {
    if (subject_) {
        it_ = subject_->Register(cb);
    }
}

// Observer析构函数实现
Observer::~Observer() {
    if (registered_ && subject_) {
        subject_->Unregister(it_);
        registered_ = false;
    }
}

// Observer移动构造函数实现
Observer::Observer(Observer&& other) noexcept 
    : subject_(other.subject_), it_(other.it_), registered_(other.registered_) {
    other.registered_ = false;
}

// Observer移动赋值运算符实现
Observer& Observer::operator=(Observer&& other) noexcept {
    if (this != &other) {
        // 先注销当前注册的回调
        if (registered_ && subject_) {
            subject_->Unregister(it_);
        }
        subject_ = other.subject_;
        it_ = other.it_;
        registered_ = other.registered_;
        other.registered_ = false;
    }
    return *this;
}

// 测试示例
int main() {
    Subject subject;

    // 创建两个观察者,自动注册回调
    Observer obs1(&subject, [](int val) {
        std::cout << "Observer1 received: " << val << std::endl;
    });
    Observer obs2(&subject, [](int val) {
        std::cout << "Observer2 received: " << val << std::endl;
    });

    // 触发通知
    subject.Notify(10);

    // obs1离开作用域自动析构,自动注销
    {
        Observer obs3(&subject, [](int val) {
            std::cout << "Observer3 received: " << val << std::endl;
        });
        subject.Notify(20);
    }

    // obs3已注销,不会收到通知
    subject.Notify(30);

    return 0;
}

代码逻辑解析

上述实现中,SubjectRegister方法将回调加入callbacks_列表,返回对应的迭代器。Observer构造时调用Register获取迭代器,析构时调用SubjectUnregister方法移除对应回调,整个过程无需手动干预。

注意到Observer禁止了拷贝操作,只允许移动,是因为迭代器拷贝后如果原对象析构,会导致重复注销的问题。移动操作会将原对象的注册状态置为false,避免重复注销。

使用注意事项

  • Subject的生命周期必须长于所有关联的Observer,否则Observer析构时访问悬空的subject_指针会导致未定义行为。
  • 回调函数中不要做耗时操作,否则会阻塞Notify方法的执行,影响所有观察者的通知效率。
  • 如果需要线程安全的回调列表管理,可以在SubjectRegisterUnregisterNotify方法中添加互斥锁保护。

适用场景

这种轻量级封装适合中小型C++项目中的事件通知场景,比如UI组件的事件响应、模块间的消息传递等,不需要引入复杂的第三方信号槽库,代码量小且易于维护。

C++观察者模式RAII回调列表管理信号槽修改时间:2026-07-24 06:21:35

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。