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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【FPGA开发】ZYNQ中PS与PL交互操作总结、原理浅析、仿真操作

文章目录 PL与PS交互综述交互端口性能&特点&#xff08;选择方案的凭据&#xff09;GPIO-AXI_GPDMA-DMACHP-AXI_HPACP-AXI_ACP 数据交互实验GP通过BRAMPS为主机&#xff0c;读写BRAMPL作为主机&#xff0c;读写BRAM DMA方式交互 PL与PS交互综述 网络上关于PS PL交互的教程…

【论文笔记】Large Brain Model (LaBraM, ICLR 2024)

Code: https://github.com/935963004/LaBraM Data: 无 目录 AbstractIntroductionMethodNeural tokenizer training&#xff1a;Pre-training LaBraM&#xff1a; ResultsExperimental setup&#xff1a;Pre-training result&#xff1a;Comparison with SOTA&#xff1a;Pre-t…

推荐几个 VSCode 流程图工具

Visual Studio Code&#xff08;简称VSCode&#xff09;是一个由微软开发的免费、开源的代码编辑器。 VSCode 发布于 2015 年&#xff0c;而且很快就成为开发者社区中广受欢迎的开发工具。 VSCode 可用于 Windows、macOS 和 Linux 等操作系统。 VSCode 拥有一个庞大的扩展市…

2024信创数据库TOP30之达梦DM8

近年来&#xff0c;中国信创产业快速崛起&#xff0c;其中数据库作为基础软件的重要组成部分&#xff0c;发挥了至关重要的作用。近日&#xff0c;由DBC联合CIW/CIS共同发布的“2024信创数据库TOP30”榜单正式揭晓&#xff0c;汇聚了国内顶尖的数据库企业及产品&#xff0c;成为…

将网站地址改成https地址需要哪些材料

HTTPS&#xff08;安全超文本传输协议&#xff09;是HTTP协议的扩展。它大大降低了个人数据&#xff08;用户名、密码、银行卡号等&#xff09;被拦截的风险&#xff0c;还有助于防止加载网站时的内容替换&#xff0c;包括广告替换。 在发送数据之前&#xff0c;信息会使用SSL…

RPC安全可靠的异常重试

当调用方调用服务提供方&#xff0c;由于网络抖动导致的请求失败&#xff0c;这个请求调用方希望执行成功。 调用方应该如何操作&#xff1f;catch异常再发起一次调用&#xff1f;显然不够优雅。这时可以考虑使用RPC框架的重试机制。 RPC框架的重试机制 RPC重试机制&#xff1…

【c++丨STL】priority_queue(优先级队列)的使用与模拟实现

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;C、STL 目录 前言 一、priority_queue简介 二、priority_queue的使用 构造函数(constructor) empty size top push和pop swap 仿函数的使用 三、prio…

【数据结构】【线性表】【练习】删除链表倒数第n个结点

目录 申明 题目 分析题目信息 解题思路 代码解析 技巧解析&#xff1a;创建虚拟头结点 时间复杂度分析 思考&#xff1a;能否只用一趟扫描实现&#xff1f; 双指针 双指针解题思路 代码解析 申明 该题源自力扣题库19&#xff0c;文章内容&#xff08;代码&#xff0c…

Ubuntu20.04升级glibc升级及降级的心路历程

想使用pip安装Isaac Sim&#xff0c;无奈此方法只支持 GLIBC>2.34 。使用的是Ubuntu20.04&#xff0c;使用 ldd --version 查看GLIBC版本&#xff0c;如果版本低于 2.34 则需要升级GLIBC&#xff0c;基于此开始了长达一天的尝试。 请注意&#xff0c;升级GLIBC是一个危险操作…

uniapp实现开发遇到过的问题(持续更新中....)

1. 在ios模拟器上会出现底部留白的情况 解决方案&#xff1a; 在manifest.json文件&#xff0c;找到开源码视图配置&#xff0c;添加如下&#xff1a; "app-plus" : {"safearea":{"bottom":{"offset" : "none" // 底部安…

Electron开发构建工具electron-vite(alex8088)添加VueDevTools(VitePlugin)

零、介绍 本文章的electron-vite指的是这个项目&#x1f449;electron-vite仓库&#xff0c;electron-vite网站 本文章的VueDevTools指的是VueDevTools的Vite插件版&#x1f449;https://devtools.vuejs.org/guide/vite-plugin 一、有一个用electron-vite创建的项目 略 二、…

机器学习基础05_随机森林线性回归

一、随机森林 机器学习中有一种大类叫集成学习&#xff08;Ensemble Learning&#xff09;&#xff0c;集成学习的基本思想就是将多个分类器组合&#xff0c;从而实现一个预测效果更好的集成分类器。集成算法大致可以分为&#xff1a;Bagging&#xff0c;Boosting 和 Stacking…

Linux驱动开发(9):pinctrl子系统和gpio子系统--led实验

在前面章节&#xff0c;我们有过使用寄存器去编写字符设备的经历了。这种直接在驱动代码中&#xff0c; 通过寄存器映射来对外设进行使用的编程方式&#xff0c;从驱动开发者的角度可以说是灾难。 因为每当芯片的寄存器发生了改动&#xff0c;那么底层的驱动几乎得重写。 那么…

23种设计模式速记法

前言 在软件开发的过程中&#xff0c;设计模式作为解决常见问题的通用模板&#xff0c;一直是开发者的重要工具。尤其是在面临复杂系统架构和需求变化时&#xff0c;设计模式不仅能够提升代码的可复用性和扩展性&#xff0c;还能大大提高团队之间的协作效率。然而&#xff0c;…

IntelliJ+SpringBoot项目实战(十二)--设计项目多模块依赖关系和跨模块调用服务和接口

在非微服务的项目中&#xff0c;一个应用里有多个子系统&#xff0c;例如在一个电商系中&#xff0c;有系统管理子系统、内容管理子系统和电商管理子系统&#xff0c;我们想实现这样的效果&#xff1a; &#xff08;1&#xff09;只需要启动一个SpringBoot应用&#xff0c;不需…

MACOS开发、使用常见问题汇总

MACOS常见问题 本文记录使用macos遇到的常见问题&#xff0c;后面会持续更新&#xff0c;觉得有用的可以收藏一下。 打不开xxx.app&#xff0c;因为它来自身份不明的开发者解决方法(开启任何来源) 打开终端&#xff08;Terminal&#xff09;程序 拷贝sudo spctl --master-di…

【实用数据】上市公司数字化转型双重差分准自然实验数据(2007-2022年)

测算方式&#xff1a; 参考《管理评论》丁相安&#xff08;2024&#xff09;老师研究的做法&#xff0c;企业分批逐步推动自身数字化转型是一个很好的准自然实验&#xff0c;这符合双重差分法的使用情境。 因此&#xff0c;本文使用多时点双重差分模型&#xff08;&#xff24…

PostgreSQL常用字符串函数与示例说明

文章目录 coalesce字符串位置(position strpos)字符串长度与大小写转换去掉空格(trim ltrim rtrim)字符串连接(concat)字符串替换简单替换(replace)替换指定位置长度(overlay)正则替换(regexp_replace) 字符串匹配字符串拆分split_part(拆分数组取指定位置的值)string_to_array…

一次需升级系统的wxpython安装(macOS M1)

WARNING: The scripts libdoc, rebot and robot are installed in /Users/用户名/Library/Python/3.8/bin which is not on PATH. 背景&#xff1a;想在macos安装Robot Framework &#xff0c;显示pip3不是最新&#xff0c;更新pip3后显示不在PATH上 参看博主文章末尾 MAC系统…

细说STM32单片机DMA中断收发RTC实时时间并改善其鲁棒性的另一种方法

目录 一、工程配置 二、软件代码 1、软件代码 2、usart.h 3、usart.c 4、rtc.c 三、运行与调试 1、合规的指令 2、proBuffer[0]不是 ‘#’ 或proBuffer[4]不是 ‘;’ 3、指令长度小于5 4、proBuffer[2]或proBuffer[3]至少一个不是数字 5、; 位于proBuffer…