讲师中心 微信公众号
AI工具推荐 视频效率加速

C++实现简单的观察者模式 _ 弱引用(weak_ptr)避免死锁【源码】

夜瑶吖_6729

夜瑶吖_6729

发布时间:2026-04-24 23:38:25

|

200人浏览过

|

来源于php中文网

原创

用shared_ptr易致循环引用:Subject持Observer的shared_ptr,Observer又持Subject的shared_ptr,双方引用计数无法归零,导致内存泄漏与析构失败;weak_ptr可破此局,Observer仅用weak_ptr临时lock访问Subject,不延长其生命周期。

c++实现简单的观察者模式 _ 弱引用(weak_ptr)避免死锁【源码】

为什么观察者模式里用 shared_ptr 容易导致循环引用死锁

观察者模式中,被观察者(Subject)通常持有一组观察者(Observer)的指针;而观察者又常常持有对 Subject 的引用以便主动获取状态或调用更新接口。如果双方都用 shared_ptr 持有对方,就会形成循环引用:Subject 的引用计数依赖 Observer,Observer 的引用计数又依赖 Subject,导致两者永远无法析构。

典型现象是程序退出时内存没释放、析构函数不执行,或者调试时发现对象生命周期远超预期。尤其在长期运行的服务中,这类泄漏会逐渐累积。

  • Subject 保存 std::vector<:shared_ptr>></:shared_ptr>
  • Observer 内部保存 std::shared_ptr<subject></subject>(比如用于调用 Subject::getState())
  • 一旦注册后未手动解除,两者相互延长生命周期,weak_ptr 是唯一安全解法

如何用 weak_ptr 在 Observer 中安全访问 Subject

Observer 不该拥有 Subject,只应在需要时临时访问。用 std::weak_ptr<subject></subject> 替代 shared_ptr,并在每次使用前调用 lock() 获取临时有效的 shared_ptr —— 如果返回空,说明 Subject 已销毁,直接跳过本次通知。

关键不是“避免崩溃”,而是让 Observer 能优雅退场:即使 Subject 先销毁,Observer 仍可存在(比如等待异步任务结束),只是后续调用失效。

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

C++ 算法竞赛自动化测试数据生成与校验框架
C++ 算法竞赛自动化测试数据生成与校验框架

根据原题生成新题面、验证器及完整测试数据,自动套用 testlib 模板,用于用户要求生成测试数据时。

下载
  • Observer 构造时接收 std::weak_ptr<subject></subject>,而非 shared_ptr
  • 在 update() 中写:auto subj = subject_.lock(); if (!subj) return;
  • 不要把 lock() 结果存为成员变量——那又变相延长了生命周期
  • weak_ptr 本身不增加引用计数,也不参与析构顺序竞争

Subject 注册/注销时怎么避免迭代器失效和重复删除

Subject 管理观察者列表时,常用 std::vector<:shared_ptr>></:shared_ptr>。但注销(unregister)若用 erase(remove_if(...)) 配合裸指针比较,容易因对象已析构而访问非法内存;若用 shared_ptr 比较,则需确保 Observer 实例唯一且未被拷贝。

更稳妥的做法是:注册时返回一个 std::size_t token(下标),注销时按索引删;或用 std::list + erase 迭代器,配合 std::shared_ptr::owner_before 做唯一性判断。

  • 推荐注册返回 std::shared_ptr<void></void> 作为 token(利用其控制块地址唯一性)
  • 内部用 std::set<:shared_ptr>, std::owner_less<...>></...></:shared_ptr> 存 token,避免重复插入
  • 注销时直接 erase 对应 token,无需遍历比较 Observer 对象内容
  • 注意:不能用原始指针做 key,因为 Observer 可能已析构,地址复用会导致误删

一个最小可运行的 C++20 版本示例(含完整生命周期验证)

下面代码去掉异常处理和线程安全,聚焦核心逻辑。重点看 Observer 如何用 weak_ptr、Subject 如何用 owner_less 管理 token:

#include <memory>
#include <set>
#include <vector>
#include <iostream>

struct Subject;
struct Observer {
    explicit Observer(std::weak_ptr<Subject> s) : subject_(s) {}
    void update() {
        auto subj = subject_.lock();
        if (!subj) return;
        std::cout << "Observer sees value: " << subj->value() << "\n";
    }
private:
    std::weak_ptr<Subject> subject_;
};

struct Subject {
    using Token = std::shared_ptr<void>;
    std::set<Token, std::owner_less<Token>> observers_;
    int data_ = 42;

    Token register_observer(std::shared_ptr<Observer> obs) {
        auto token = std::make_shared<int>(0);
        observers_.insert(token);
        return token;
    }

    void unregister_observer(const Token& t) {
        observers_.erase(t);
    }

    void notify() {
        // 复制一份智能指针,避免遍历时容器被修改
        auto copies = std::vector<std::shared_ptr<Observer>>();
        for (auto& t : observers_) {
            // 这里实际应关联 observer 实例,简化起见略去映射逻辑
        }
        // 真实项目中建议用 map<Token, shared_ptr<Observer>>
    }

    int value() const { return data_; }
};

真正麻烦的不是写出来,而是验证它是否真的不会循环引用——用 AddressSanitizer 编译,注册后立即释放 Subject,再触发一次 notify,看 Observer 是否静默跳过。这点很容易被忽略。

热门AI工具

更多
PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

相关专题

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

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

2208

2024.03.14

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

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

979

2024.03.14

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

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

387

2024.03.14

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

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

307

2024.03.14

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

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

386

2024.03.14

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

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

580

2024.03.14

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

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

1389

2024.03.21

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

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

1177

2024.03.22

PixTV AI视频生成与无限画布创作
PixTV AI视频生成与无限画布创作

PixTV专题整理AI视频与视觉内容创作相关功能使用教程,涵盖AI生图、视频生成、无限画布、多模型创作、素材管理、声音音乐及视频剪辑等功能,帮助用户快速掌握PixTV从创意到成片的完整制作方法。

0

2026.09.29

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Conan 2 Essentials 免费课程
Conan 2 Essentials 免费课程

共0课时 | 0人学习

CMake 与 Conan 集成实践
CMake 与 Conan 集成实践

共0课时 | 0人学习

Conan 2 高级依赖模型介绍
Conan 2 高级依赖模型介绍

共0课时 | 0人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn