0

0

c++如何实现一个简单的信号槽(Signal-Slot)机制? (观察者模式)

冰火之心

冰火之心

发布时间:2026-01-12 13:47:38

|

264人浏览过

|

来源于php中文网

原创

不能直接用 std::function + std::vector 存槽函数,因裸指针无法感知被观察对象生命周期,导致析构后调用引发未定义行为;安全方案是用 std::weak_ptr + std::shared_ptr 实现弱引用绑定,并封装 Connection 自动管理连接生命周期。

c++如何实现一个简单的信号槽(signal-slot)机制? (观察者模式)

为什么不能直接用 std::function + std::vector 存槽函数?

可以存,但会立刻遇到生命周期管理问题:如果 Slot 是某个对象的成员函数(比如 &obj.onDataReady),而 obj 被提前析构,后续信号触发时调用已释放对象的成员函数 → 未定义行为(常见表现是段错误或静默崩溃)。裸指针或原始 std::function 无法感知被观察对象是否还活着。

如何安全绑定成员函数并自动解绑?

核心是引入弱引用语义。C++11 起,std::weak_ptr 配合 std::shared_ptr 是标准解法:观察者对象需继承自 std::enable_shared_from_this,信号类存储 std::weak_ptr + 成员函数指针,每次触发前用 lock() 检查对象是否有效。

  • 信号类中不直接存 std::function,而是存 std::pair<:weak_ptr>, void (T::*)()> 这类组合(实际需类型擦除)
  • 更实用的做法是封装一个 Connection 对象,内部持有一个 std::weak_ptr,并在析构时从信号的槽列表中移除自己
  • 避免手动管理连接生命周期:让 connect() 返回一个可移动、不可复制的 Connection,用户持有它即保持绑定;一旦 Connection 离开作用域,自动断开

一个最小可行的 Signal 类模板实现

以下代码省略异常处理和线程安全(多线程需加 std::mutex),聚焦核心逻辑:

template
class Signal {
private:
    struct SlotBase {
        virtual ~SlotBase() = default;
        virtual void invoke(Args... args) = 0;
        virtual bool is_alive() const = 0;
    };

    template
    struct Slot final : SlotBase {
        std::weak_ptr obj_;
        Func func_;

        Slot(std::shared_ptr obj, Func&& f) 
            : obj_(std::move(obj)), func_(std::forward(f)) {}

        void invoke(Args... args) override {
            if (auto ptr = obj_.lock()) {
                std::invoke(func_, *ptr, std::forward(args)...);
            }
        }

        bool is_alive() const override {
            return obj_.lock() != nullptr;
        }
    };

    std::vector> slots_;

public:
    template
    void connect(std::shared_ptr obj, Func&& f) {
        slots_.push_back(std::make_unique>>(
            std::move(obj), std::forward(f)));
    }

    void emit(Args... args) {
        // 注意:此处不删除失效 slot,仅跳过;真实项目建议定期清理
        for (auto& s : slots_) {
            if (s->is_alive()) {
                s->invoke(std::forward(args)...);
            }
        }
    }
};

使用时,被观察对象必须是 std::shared_ptr 管理的(例如继承 std::enable_shared_from_this),否则无法构造 std::weak_ptr

MOKI
MOKI

MOKI是美图推出的一款AI短片创作工具,旨在通过AI技术自动生成分镜图并转为视频素材。

下载

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

容易忽略的关键细节

信号触发期间若槽函数内部又调用 connect()disconnect()(比如在槽里删自己),会导致迭代器失效或内存访问越界。解决方式有二:

  • 延迟清理:把待移除的 slot 标记为 “dead”,emit() 结束后统一擦除
  • 用索引而非迭代器遍历,或改用 std::list 配合 erase() 安全删除
  • 更彻底的方案是禁止槽函数修改信号本身 —— 这需要文档约束,而非强制语法限制

另外,std::invoke 是 C++17 引入的,若用 C++11/14,需手写函数对象调用逻辑(如用 std::bind 包装再调用,但性能稍差)。

相关专题

更多
线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

480

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

143

2025.12.24

function是什么
function是什么

function是函数的意思,是一段具有特定功能的可重复使用的代码块,是程序的基本组成单元之一,可以接受输入参数,执行特定的操作,并返回结果。本专题为大家提供function是什么的相关的文章、下载、课程内容,供大家免费下载体验。

473

2023.08.04

js函数function用法
js函数function用法

js函数function用法有:1、声明函数;2、调用函数;3、函数参数;4、函数返回值;5、匿名函数;6、函数作为参数;7、函数作用域;8、递归函数。本专题提供js函数function用法的相关文章内容,大家可以免费阅读。

163

2023.10.07

Java 项目构建与依赖管理(Maven / Gradle)
Java 项目构建与依赖管理(Maven / Gradle)

本专题系统讲解 Java 项目构建与依赖管理的完整体系,重点覆盖 Maven 与 Gradle 的核心概念、项目生命周期、依赖冲突解决、多模块项目管理、构建加速与版本发布规范。通过真实项目结构示例,帮助学习者掌握 从零搭建、维护到发布 Java 工程的标准化流程,提升在实际团队开发中的工程能力与协作效率。

3

2026.01.12

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

97

2026.01.09

c++框架学习教程汇总
c++框架学习教程汇总

本专题整合了c++框架学习教程汇总,阅读专题下面的文章了解更多详细内容。

53

2026.01.09

学python好用的网站推荐
学python好用的网站推荐

本专题整合了python学习教程汇总,阅读专题下面的文章了解更多详细内容。

139

2026.01.09

学python网站汇总
学python网站汇总

本专题整合了学python网站汇总,阅读专题下面的文章了解更多详细内容。

12

2026.01.09

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号