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

在 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 观察主题对象,从而实现了避免循环引用和内存泄漏的功能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IDE配置tomcat

1.导航到 Tomcat 安装目录 E:\apache-tomcat-9.0.95-windows-x64\apache-tomcat-9.0.95 2.启动 Tomcat 服务&#xff1a;bin\startup.bat

python读取Oracle库并生成API返回Json格式

一、安装必要的库 首先&#xff0c;确保已经安装了以下库&#xff1a; 有网模式 pip install flask pip install gevent pi install cx_Oracle离线模式&#xff1a; 下载地址&#xff1a;https://pypi.org/simple/flask/ # a. Flask Werkzeug-1.0.1-py2.py3-none-any.whl J…

MAC借助终端上传jar包到云服务器

前提&#xff1a;保证工程本地已打包完成&#xff1a;图中路径即为项目的target目录下已准备好的jar包 第一步&#xff1a;打开终端&#xff08;先不要连接自己的服务器&#xff09;&#xff0c;输入下面的上传命令&#xff1a; scp /path/to/local/app.jar username192.168.1…

Python数据分析NumPy和pandas(四十、Python 中的建模库statsmodels 和 scikit-learn)

主要学习两个流行的建模工具包&#xff0c;statsmodels 和 scikit-learn。 一、pandas 与模型代码之间的接口 模型开发的常见工作流程是使用 pandas 进行数据加载和清理&#xff0c;然后再切换到建模库来构建模型本身。模型开发过程的一个重要部分在机器学习中称为特征工程&a…

实操案例|TinyVue树表+动态行合并

本文由孟智强同学原创。 背景 团队某个小项目切换 UI 框架&#xff0c;要将 Element 换成 TinyVue。期间遇到一个树表形式的业务表格&#xff0c;支持多级下钻&#xff0c;且第一列有合并行。当初用 Element 实现这个表格时费了一些周折&#xff0c;料想 TinyVue 上场应该也不…

Mesh路由组网

Mesh无线网格网络&#xff0c;多跳&#xff08;multi-hop&#xff09;网络&#xff0c;为解决全屋覆盖信号&#xff0c;一般用于家庭网络和小型企业 原理 网关路由器&#xff08;主路由&#xff0c;连接光猫&#xff09;&#xff0c;Mesh路由器&#xff08;子路由&#xff0c;…

基于Windows系统用C++做一个点名工具

目录 一、前言 二、主要技术点 三、准备工作 四、主界面 1.绘制背景图 2、实现读取花名册功能 3.实现遍历花名册功能 4.实现储存功能 4.1创建数据库 4.2存储数据到数据库表 4.3读取数据库表数据 一、前言 人总是喜欢回忆过去&#xff0c;突然回忆起…

11.9K Star!强大的 Web 爬虫工具 FireCrawl:为 AI 训练与数据提取提供全面支持

在这个信息爆炸的时代&#xff0c;数据就是力量。尤其是对于开发者来说&#xff0c;获取并利用好数据&#xff0c;就意味着拥有更多的主动权和竞争力。 无论是用来训练大语言模型&#xff0c;还是用于增强检索生成&#xff08;RAG&#xff09;&#xff0c;数据都扮演着至关重要…

云原生之k8s服务管理

文章目录 服务管理Service服务原理ClusterIP服务 对外发布应用服务类型NodePort服务Ingress安装配置Ingress规则 Dashboard概述 认证和授权ServiceAccount用户概述创建ServiceAccount 权限管理角色与授权 服务管理 Service 服务原理 容器化带来的问题 自动调度&#xff1a;…

前端面试题整理-前端异步编程

1. 进程、线程、协程的区别 在并发编程领域&#xff0c;进程、线程和协程是三个核心概念&#xff0c;它们在资源管理、调度和执行上有着本质的不同。 首先&#xff0c;进程是操作系统进行资源分配和调度的独立单位&#xff08;资源分配基本单位&#xff09;&#xff0c;每个进…

动静态库:选择与应用的全方位指南

目录 1 软链接 1.1 软链接的建立方式和观察现象 1.2 软链接的原理 2 硬链接 2.1 硬链接的建立方式和观察现象 2.2 硬链接的本质 2.3 我们用户不能给目录建立硬链接 3. 动静态库复习 4 动静态库的制作 4.1 静态库的制作与使用 4.1.2 打包 4.1.3 静态库的使用 4.2 动…

【ROS2】多传感器融合、实现精准定位:robot_localization

1、简述 robot_localization在SLAM建图、导航中常用于将多个传感器融合(IMU、里程计、深度相机、GPS等),以提高定位精度,为机器人提供了在三维空间中的非线性状态估计 robot_localization包含两个状态估计节点: ekf_localization_node:扩展卡尔曼滤波(EKF),缺点是非…

极客大挑战2024wp

极客大挑战2024wp web 和misc 都没咋做出来&#xff0c;全靠pwn✌带飞 排名 密码学和re没做出几个&#xff0c;就不发了 web ez_pop 源代码 <?php Class SYC{public $starven;public function __call($name, $arguments){if(preg_match(/%|iconv|UCS|UTF|rot|quoted…

40分钟学 Go 语言高并发:并发下载器开发实战教程

并发下载器开发实战教程 一、系统设计概述 1.1 功能需求表 功能模块描述技术要点分片下载将大文件分成多个小块并发下载goroutine池、分片算法断点续传支持下载中断后继续下载文件指针定位、临时文件管理进度显示实时显示下载进度和速度进度计算、速度统计错误处理处理下载过…

李宏毅机器学习课程知识点摘要(1-5集)

前5集 过拟合&#xff1a; 参数太多&#xff0c;导致把数据集刻画的太完整。而一旦测试集和数据集的关联不大&#xff0c;那么预测效果还不如模糊一点的模型 所以找的数据集的量以及准确性也会影响 由于线性函数的拟合一般般&#xff0c;所以用一组函数去分段来拟合 sigmoi…

Spring Boot教程之五:在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序

在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序 IntelliJ IDEA 是一个用 Java 编写的集成开发环境 (IDE)。它用于开发计算机软件。此 IDE 由 Jetbrains 开发&#xff0c;提供 Apache 2 许可社区版和商业版。它是一种智能的上下文感知 IDE&#xff0c;可用于在各种应用程序…

本地Docker部署开源WAF雷池并实现异地远程登录管理界面

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

如何快速将Excel数据导入到SQL Server数据库

工作中&#xff0c;我们经常需要将Excel数据导入到数据库&#xff0c;但是对于数据库小白来说&#xff0c;这可能并非易事&#xff1b;对于数据库专家来说&#xff0c;这又可能非常繁琐。 这篇文章将介绍如何帮助您快速的将Excel数据导入到sql server数据库。 准备工作 这里&…

[产品管理-91]:产品经理的企业运营的全局思维-1

目录 前言&#xff1a;企业架构图 产品经理的企业运营全局思维 1、用户 - 用户价值与体验&#xff1a;真正的需求&#xff0c;真正的问题&#xff0c;一切的原点 2、大势 - 顺应宏观大势&#xff1a;政策趋势、行业趋势、技术趋势 3、市场 - 知己知彼&#xff1a;市场调研…

简单实现vue2响应式原理

vue2 在实现响应式时&#xff0c;是根据 object.defineProperty() 这个实现的&#xff0c;vue3 是通过 Proxy 对象实现&#xff0c;但是实现思路是差不多的&#xff0c;响应式其实就是让 函数和数据产生关联&#xff0c;在我们对数据进行修改的时候&#xff0c;可以执行相关的副…