std::weak_ptr应用于观察者模式的示例

news2024/11/24 4:54:50

在 C++ 中,std::weak_ptr 是一个智能指针,用来观察由 std::shared_ptr 所管理的对象,而不增加该对象的引用计数。它通常用于避免 循环引用强引用计数的增长,特别在实现观察者模式时,weak_ptr 可以帮助观察者避免不必要的对象生命周期延长。

以下是如何使用 std::weak_ptr 来实现一个简单的观察者模式的示例。

观察者模式简介

观察者模式是一种行为设计模式,其中一个对象(主题或发布者)维护一组依赖对象(观察者),并在状态变化时通知这些观察者。主题对象的生命周期通常较长,而观察者对象的生命周期通常较短,使用 weak_ptr 可以确保观察者在主题对象销毁时不会导致内存泄漏。

示例:使用 weak_ptr 实现观察者模式

下面是一个简单的例子,其中我们有一个 Subject 类(主题),它可以注册多个 Observer(观察者)。每个观察者是通过 std::weak_ptr 来持有的,避免循环引用。

1. 定义 ObserverSubject
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>

class Observer {
public:
    virtual void update(int value) = 0;
    virtual ~Observer() = default;
};

class Subject {
private:
    std::vector<std::weak_ptr<Observer>> observers;

public:
    void addObserver(const std::shared_ptr<Observer>& observer) {
        observers.push_back(observer);
    }

    void removeObserver(const std::shared_ptr<Observer>& observer) {
        observers.erase(std::remove_if(observers.begin(), observers.end(),
            [&](const std::weak_ptr<Observer>& o) { return o.lock() == observer; }), observers.end());
    }

    void notify(int value) {
        for (auto& weakObserver : observers) {
            if (auto observer = weakObserver.lock()) {  // 如果观察者仍然存在
                observer->update(value);
            }
        }
    }
};
2. 定义具体的 Observer 实现
class ConcreteObserver : public Observer {
private:
    std::string name;

public:
    ConcreteObserver(const std::string& name) : name(name) {}

    void update(int value) override {
        std::cout << "Observer " << name << " received update with value: " << value << std::endl;
    }
};
3. 使用 SubjectObserver
int main() {
    // 创建主题对象
    std::shared_ptr<Subject> subject = std::make_shared<Subject>();

    // 创建观察者对象
    std::shared_ptr<ConcreteObserver> observer1 = std::make_shared<ConcreteObserver>("Observer1");
    std::shared_ptr<ConcreteObserver> observer2 = std::make_shared<ConcreteObserver>("Observer2");

    // 注册观察者
    subject->addObserver(observer1);
    subject->addObserver(observer2);

    // 通知观察者
    subject->notify(10);  // 所有观察者都会接收到通知

    // 移除一个观察者
    subject->removeObserver(observer1);

    // 通知剩余的观察者
    subject->notify(20);  // 只有 Observer2 会接收到通知

    // observer2 会自动销毁,而 observer1 的析构函数不会被触发
    return 0;
}

解释

  1. 观察者和主题:

    • Observer 是一个抽象类,定义了 update 方法,所有具体的观察者类都需要实现该方法。
    • Subject 是主题类,管理所有的观察者。它使用 std::weak_ptr<Observer> 来存储观察者,以避免观察者对象的生命周期被 Subject 锁住。
  2. weak_ptr 使用:

    • Subject 中,观察者是通过 std::weak_ptr<Observer> 存储的。weak_ptr 不会增加观察者的引用计数,避免了循环引用的问题。使用时,需要调用 lock() 方法来获取一个有效的 shared_ptr,如果观察者已经被销毁(引用计数为 0),lock() 会返回一个空指针。
  3. 观察者的生命周期管理:

    • main 函数中,我们创建了两个观察者对象,并注册到主题对象中。当我们通过 subject->notify() 向观察者发送通知时,只有有效的观察者会接收到通知。
    • 当一个观察者被从 Subject 中移除后,它将不再接收到通知。
    • std::weak_ptr 确保即使观察者对象在通知过程中销毁,它也不会阻止观察者对象的销毁。
  4. 移除观察者:

    • removeObserver 方法移除了特定的观察者。我们使用 std::remove_if 来从观察者列表中删除对应的观察者。如果该观察者已经被销毁,lock() 将返回 nullptr,该观察者将不会再被通知。

总结

使用 std::weak_ptr 可以有效地避免观察者模式中的循环引用问题,避免因为观察者持有主题对象的 shared_ptr 而导致无法销毁的问题。在这个示例中,Subject 类管理观察者的生命周期,而每个 Observer 使用 weak_ptr 观察主题对象,从而实现了避免循环引用和内存泄漏的功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2246442.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C#桌面应用制作计算器进阶版01

基于C#桌面应用制作计算器做出了少量改动&#xff0c;其主要改动为新增加了一个label控件&#xff0c;使其每一步运算结果由label2展示出来&#xff0c;而当点击“”时&#xff0c;最终运算结果将由label1展示出来&#xff0c;此时label清空。 修改后运行效果 修改后全篇代码 …

应用商店双弹窗“APP在向用户申请权限时未同步告知用户申请此权限的理由”驳回uni-app应用上线的解决方法

目录 问题分析 解决方法 下载插件包&#xff1a;x-perm-apply-instr 将插件包导入进你项目中的uni_modules文件夹 在项目中的main.js文件中添加以下代码 完成 其它注意事项 addPermisionInterceptor 添加 uniApi 调用拦截 removePermisionInterceptor 移除 uniApi 调用…

dockerfile构建Nginx镜像练习二(5-2)

环境准备&#xff1a; (1)保证拥有centos基础镜像 docker images | grep centos (2)服务器保证可以连接外网 1.创建工作目录 mkdir nginx cd nginx 2.在工作目录中创建并编写Dockerfile文件 vim dockerfile #定义基础镜像 FROM centos:7#维护者信息(可缺省) MAINTAINER d…

Java 调用 MULTIPART_FORM_DATA 接口

以 QAnthing 上传文件&#xff08;POST&#xff09;接口为例&#xff0c;展示Java如何调用上传文件接口。 接口文档如下&#xff1a; QAnthign接口文档地址 编码 RestTemplate 版 /** * * param url 接口地址 * param filePath 文件本地路径 */ public void uploadFile(S…

Spring Framework 的版本历史和JDK、Springboot对应关系

spring 历史版本迭代 版本版本特性Spring Framework 1.01. 所有代码都在一个项目中2. 支持核心功能IoC、AOP3. 内置支持Hibernate、iBatis等第三方框架4. 对第三方技术简单封装。如&#xff1a;JDBC、Mail、事务等5. 只支持XML配置方式。6.主要通过 XML 配置文件来管理对象和依…

SpringSecurity创建一个简单的认证应用

1、SpringSecurity 的简介 Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架&#xff0c;它是Spring项目组中用来提供安全认证服务的框架&#xff0c;能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案。 Spring Security 的前身是 Acegi …

力扣 LeetCode 236. 二叉树的最近公共祖先(Day10:二叉树)

解题思路&#xff1a; 后序遍历 注意&#xff1a; p和q其中一个就是它们的公共祖先的情况也考虑到了&#xff0c;假设q是公共祖先&#xff0c;遇到q就直接返回&#xff0c;相当于是下面一边为空&#xff0c;一边不为空的情况&#xff0c;返回不为空就一边即可 class Solutio…

AIGC(生成式AI)试用 18 -- AI Prompt

"忘了"&#xff0c;“记不清了”&#xff0c;“有点印像” “能给点提示吗&#xff1f;” ...... “哦&#xff0c;想起来了&#xff0c;是这样的。。。。。。” 这就是提示的作用&#xff1a;通过关键信息、结构化信息提示&#xff0c;引导完整的、…

Telegram bot Mini-App开发实践---Telegram简单介绍与初始化小程序获取window.Telegram.WebApp对象并解析

➡️【好看的灵魂千篇一律,有趣的鲲志一百六七!】- 欢迎认识我~~ 作者:鲲志说 (公众号、B站同名,视频号:鲲志说996) 科技博主:极星会 星辉大使 后端研发:java、go、python、TS,前电商、现web3 主理人:COC杭州开发者社区主理人 、周周黑客松杭州主理人、 AI爱好…

在Windows环境下打包Qt C++项目为独立可执行文件的完整指南

目录 1. 配置Qt环境变量步骤&#xff1a; 2. 使用Release模式编译项目步骤&#xff1a; 3. 使用windeployqt工具收集依赖项步骤&#xff1a; 4. 精简复制后的文件目录方法一&#xff1a;使用windeployqt的选项方法二&#xff1a;手动删除不必要的文件方法三&#xff1a;使用静态…

多摩川编码器协议及单片机使用

参考&#xff1a; https://blog.csdn.net/qq_28149763/article/details/132718177 https://mp.weixin.qq.com/s/H4XoR1LZSMH6AxsjZuOw6g 1、多摩川编码器协议 多摩川数据通讯是基于485 硬件接口标准NRZ 协议&#xff0c;通讯波特率为2.5Mbps 的串行通讯&#xff0c;采用差分两…

2024年11月22日Github流行趋势

项目名称&#xff1a;twenty 项目维护者&#xff1a;charlesBochet, lucasbordeau, Weiko, FelixMalfait, bosiraphael 项目介绍&#xff1a;正在构建一个由社区驱动的现代Salesforce替代方案。 项目star数&#xff1a;22,938 项目fork数&#xff1a;2,413 项目名称&#xff1…

使用Kubernetes部署第一个应用

目录 前提条件 启动集群 部署 nginx 应用 创建 YAML 文件 应用 YAML 文件 查看部署结果 理解Pods 相关命令 公布应用程序 问题背景 Kubernetes Service&#xff08;服务&#xff09;概述 服务和标签 为Deployment 创建一个 Service 伸缩应用程序 Scaling&#x…

第T8周:Tensorflow实现猫狗识别(1)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 具体实现 &#xff08;一&#xff09;环境 语言环境&#xff1a;Python 3.10 编 译 器: PyCharm 框 架: &#xff08;二&#xff09;具体步骤 from absl.l…

使用 OpenAI 进行数据探索性分析(EDA)

探索性数据分析&#xff08;Exploratory Data Analysis, 简称 EDA&#xff09;是数据分析中不可或缺的环节&#xff0c;帮助分析师快速了解数据的分布、特征和潜在模式。传统的 EDA 通常需要手动编写代码或使用工具完成。现在&#xff0c;通过 OpenAI 的 GPT-4 模型&#xff0c…

力扣-Hot100-栈【算法学习day.40】

前言 ###我做这类文档一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&am…

低速接口项目之串口Uart开发(四)——UART串口实现FPGA内部AXILITE寄存器的读写控制

本节目录 一、设计背景 二、设计思路 三、逻辑设计框架 四、仿真验证 五、上板验证 六、往期文章链接本节内容 一、设计背景 通常&#xff0c;芯片手册或者IP都会提供一系列的用户寄存器以及相关的定义&#xff0c;用于软件开发人员进行控制底层硬件来调试&#xff0c;或封装…

记录第一次安装laravel项目

window系统 Laravel中文文档&#xff1a;https://laravel-docs.catchadmin.com/docs/11/getting-started/installation 1.使用composer安装全局laravel composer global require laravel/installer2.安装完成后在命令行输入laravel&#xff0c;如果报错&#xff1a;laravel不是…

PDF电子发票信息转excel信息汇总

PDF电子发票信息提取&#xff0c;支持将pdf发票文件夹下的剩所有发票&#xff0c;转为excel格式的信息&#xff0c;对于发票量比较大&#xff0c;不好统计&#xff0c;需要一个一个去统计的情况&#xff0c;可节省2个点以上的时间&#xff0c;一次下载&#xff0c;终身有效。 使…

性能优化(二):ANR

介绍 ANR全称Application Not Responding&#xff0c;意思就是程序未响应。如果一个应用无法响应用户的输入&#xff0c;系统就会弹出一个ANR对话框&#xff0c;用户可以自行选择继续等待亦或者是停止当前程序。 Android系统会监控程序的响应状况&#xff0c;一旦出现下面情况…