weak_ptr 与 一个难发现的错误(循环依赖问题)笔记

推荐B站视频:7.weak_ptr与一个非常难发现的错误_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV18B4y187uL/?p=7&spm_id_from=pageDriver&vd_source=a934d7fc6f47698a29dac90a922ba5a3一、weak_ptr    

  • weak_ptr并不拥有所有权
  • 并不能调用 -> 和 解引用*

准备好头文件和源文件:

  • cat.h
#ifndef CAT_H
#define CAT_H
#include <string>
#include <iostream>
class Cat{
public:Cat(std::string name);Cat() = default;~Cat();void catInfo() const {std::cout<<"cat info name : "<<m_name<<std::endl;}std::string get_name() const{return m_name;}void set_cat_name(const std::string &name) {this->m_name = name;}
private:std::string m_name{"Mimi"};
};
#endif
  • cat.cpp
#include "cat.h"
Cat::Cat(std::string name) :m_name(name) {std::cout<<"Constructor of Cat : "<<m_name<<std::endl;
}Cat::~Cat() {std::cout<<"Destructor of Cat"<<std::endl;
}
  • main.cpp
#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {std::shared_ptr<Cat> s_p_c1 = std::make_shared<Cat>("c1");std::weak_ptr<Cat> w_p_c1(s_p_c1);// use_count()cout<<"w_p_c1: " << w_p_c1.use_count() << endl; // 1cout<<"s_p_c1: " << s_p_c1.use_count() << endl; // 1// w_p_c1->catInfo();// error C2039: "catInfo": 不是 "std::weak_ptr<Cat>" 的成员std::shared_ptr<Cat> s_p_c2 = w_p_c1.lock();cout<<"w_p_c1: " << w_p_c1.use_count() << endl; // 2cout<<"s_p_c1: " << s_p_c1.use_count() << endl; // 2cout<<"s_p_c2: " << s_p_c2.use_count() << endl; // 2cout<<"over~"<<endl; return 0;
}

二、一个难发现的错误(循环依赖问题

(1)weak_ptr   为什么会存在呢?

  • A类中有一个需求需要存储其他A类对象的信息
  • 如果使用shared_ptr,那么在销毁时会遇到循环依赖问题(Cyclic dependency problem)
  • 所以我们这里需要用一个不需要拥有所有权的指针来标记该同类对象
    • weak_ptr可以通过lock()函数来提升为shared_ptr(类型转换)

比方说我是一个Person,需要存储朋友的信息,需要用一个指针来指向另外一个人类,如果使用shared_ptr,那么在销毁时会遇到循环依赖问题(Cyclic dependency problem)。我在销毁的时候,我需要销毁我的朋友,我的朋友也需要销毁我,这样就出现了循环依赖问题。不知道谁先销毁,谁后销毁。所以我们这里需要用一个不需要拥有所有权的指针来标记该同类对象。

修改头文件cat.h

#ifndef CAT_H
#define CAT_H
#include <string>
#include <iostream>
#include <memory>
class Cat{
public:Cat(std::string name);Cat() = default;~Cat();void catInfo() const {std::cout<<"cat info name : "<<m_name<<std::endl;}std::string get_name() const{return m_name;}void set_cat_name(const std::string &name) {this->m_name = name;}void set_friend(std::shared_ptr<Cat> cat) {   // 增加该函数m_friend = cat;}
private:std::string m_name{"Mimi"};std::shared_ptr<Cat> m_friend; // 增加该变量
};
#endif

main.cpp

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {std::shared_ptr<Cat> c3 = std::make_shared<Cat>("C3");std::shared_ptr<Cat> c4 = std::make_shared<Cat>("C4");cout<<"over~"<<endl; return 0;
}

 执行结果,可以正常调用析构函数:

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : C3
Constructor of Cat : C4
over~
Destructor of Cat
Destructor of Cat
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

 可是如果让C3和C4互为朋友

#include <iostream>
#include <memory>
#include "cat.h"
using namespace std;
int main(int argc,char* argv[]) {std::shared_ptr<Cat> c3 = std::make_shared<Cat>("C3");std::shared_ptr<Cat> c4 = std::make_shared<Cat>("C4");c3->set_friend(c4);c4->set_friend(c3);cout<<"over~"<<endl; return 0;
}

执行结果,发现无法正常调用析构函数:

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : C3
Constructor of Cat : C4
over~
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

 (2)解决方案:将头文件的m_friendshared_ptr修改成weak_ptr即可

std::shared_ptr<Cat> m_friend; ||||  (修改成这样)||
std::weak_ptr<Cat> m_friend; 

执行结果,发现可以正常调用析构函数:

PS D:\Work\C++UserLesson\cppenv\bin\Debug> ."D:/Work/C++UserLesson/cppenv/bin/Debug/app.exe"
Constructor of Cat : C3
Constructor of Cat : C4
over~
Destructor of Cat
Destructor of Cat
PS D:\Work\C++UserLesson\cppenv\bin\Debug>

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

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

相关文章

ACL--访问控制列表概述、组成、分类、应用

目录 一、ACL概述 二、ACL的组成 三、ACL分类 四、举例说明 1、基于标准ACL和基础的高级ACL应用 2、基于端口的ACL 一、ACL概述 访问控制列表ACL&#xff08;Access Control List&#xff09;是由一条或多条规则组成的集合。所谓规则&#xff0c;是指描述报文匹配条件的…

黑马程序员——javase进阶——day02——关键字,接口,代码块,枚举

目录&#xff1a; Java中的关键字 static关键字final关键字Java中的权限修饰符代码块 构造代码块静态代码块接口 接口的介绍接口的定义和特点接口的成员特点接口的案例接口中成员方法的特点枚举随堂小记 继承方法重写抽象类模板设计模式staticfinal权限修饰符接口回顾上午内容…

大数据开发之Spark(完整版)

第 1 章&#xff1a;Spark概述 1.1 什么是spark 回顾&#xff1a;hadoop主要解决&#xff0c;海量数据的存储和海量数据的分析计算。 spark是一种基于内存的快速、通用、可扩展的大数据分析计算引擎。 1.2 hadoop与spark历史 hadoop的yarn框架比spark框架诞生的晚&#xff…

Objective-C方法的声明实现及调用

1.无参数的方法 1)声明 a.位置&#xff1a;在interface括弧的外面 b.语法&#xff1a; - (返回值类型)方法名称; interface Person : NSObject -(void) run; end 2)实现 a.位置&#xff1a;在implementation中实现 b.语法&#xff1a;加大括弧将方法实现的代码写在大括孤之中 …

KernelGPT: LLM for Kernel Fuzzing

KernelGPT: Enhanced Kernel Fuzzing via Large Language Models 1.Introduction2.Background2.1.Kernel and Device Drivers2.2.Kernel Fuzzing2.2.1.Syzkaller规约2.2.2.规约生成 3.Approach3.1.Driver Detection3.2.Specification Generation3.2.1.Command Value3.2.2.Argum…

基于静态顺序表实现通讯录

目录 一、设计框架 1、功能要求​ 2、菜单函数的实现 二、头文件实现​ Contact.h SeqList.h 三、Test.h 四、通讯录的初始化和销毁 五、增加通讯录 六、在通讯录中查找姓名下标 七、删除通讯录 八、显示通讯录 九、查找通讯录 一、设计框架 test.c&#xff1a;通…

《尊思想人文地理环境》新书亮相,叶无为集30年智慧破解环境密码

在探索人与自然和谐共生的今天&#xff0c;叶无为教授的新作《尊思想人文地理环境》应时而生&#xff0c;为读者揭开了地理环境与人文发展之间深刻联系的神秘面纱。本书集结了作者三十多年的实战经验&#xff0c;通过易医体系对大自然的山川河流进行独到解析&#xff0c;融合传…

飞越天空之城

欢迎来到程序小院 飞越天空之城 玩法&#xff1a;左边的按钮是控制小人儿飞起来的方向的&#xff0c;右边的按钮是控制它飞的高度的&#xff0c; 左边控制在正上方时可以让小人儿沿着一个方向飞跃&#xff0c;否则会撞到两边的黑墙&#xff0c; 右边的按钮如果加足够的话&…

GPTs大受欢迎但问题多,企服厂商的AI Agent更被B端客户器重

2023年11月&#xff0c;OpenAI在首届开发者大会上推出了GPTs和Assitant API&#xff0c;不仅改写了AI Agent的构建范式&#xff0c;也把AI智能体的应用推向一个新高潮。 GPTs和GPT商店&#xff0c;使得用户无需编码通过自然语言就能创建并拥有多个专属私人助理&#xff0c;且可…

【Servlet】如何编写第一个Servlet程序

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【Servlet】 本专栏旨在分享学习Servlet的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; Servlet是Java编写的服务器端…

5.【SpringBoot3】文件上传

1. 文件上传到本地 需求分析 在用户更换头像或发布文章时&#xff0c;需要携带一个图片的 url 地址&#xff0c;该 url 地址是当用户访问文件上传接口&#xff0c;将图片上传成功后&#xff0c;服务器返回的地址。所以&#xff0c;后台需要提供一个文件上传接口&#xff0c;用…

Android HIDL概述与绑定模式的实现

一、前言 Android O(8.0) 版本之后&#xff0c;底层实现有了比较大的变化&#xff0c;最显著的一个方面就是 HIDL 机制的全面实施。本文对于理解系统源码中 Gnss、Usb、Camera 等模块的工作原理有极大帮助。 二、HIDL 设计目的 在 Android O(8.0) 之前系统的升级牵扯多方协作…

Python tkinter (5) 选项按钮与复选框

Python的标准Tk GUI工具包的接口 tkinter系列文章 python tkinter窗口简单实现 Python tkinter (1) —— Label标签 Python tkinter (2) —— Button标签 Python tkinter (3) —— Entry标签 Python tkinter (4) —— Text控件 目录 CheckButton 简单示例 获取选中 Ra…

RBD —— Visualizing fractured geometry

RBD Exploded View&#xff08;与Exploded View SOP类似&#xff09;从中心炸开几何体&#xff0c;以更好查看被破碎和约束的碎块&#xff1b; 可视化高精度和低精度几何体的不同&#xff0c;Show Proxy Geometry显示代理几何体&#xff1b; Show Constraints显示约束&#xff…

6.jmeter非GUI命令及Beanshell组件

一、非GUI&#xff08;界面&#xff09;命令详解 1. -n 使用非gui方式&#xff0c;不能单独使用&#xff0c;必须和-t&#xff08;指定jmeter的脚本&#xff09;一起用。 #cmd命令行模式下&#xff0c;进入存放测试jmx文件的目录下 jmeter -n -t hello.jmx只会生成一个log日…

数据结构实验八:排序的应用

目录 一、实验目的 二、实验原理 1.直接插入排序 2.快速排序 三、实验内容 实验1 代码 截图 实验2 代码 截图 一、实验目的 1、掌握排序的基本概念&#xff1b; 2&#xff0e;掌握并实现以下排序算法&#xff1a;直接插入排序、快速排序。 二、实验原理 1.直接插…

如何选择便捷安全的黄金交易平台?

黄金交易平台的介绍 黄金交易平台是一个提供方便、安全的方式进行黄金交易的网上平台。 投资者可以通过这些平台进行黄金的买卖&#xff0c;参与黄金市场的投资活动。 这些平台提供了一个简单易用的界面&#xff0c;让投资者可以方便地进行交易操作。 选择合适的黄金交易平台…

小土堆pytorch学习笔记002

1、TensorBoard的使用 &#xff08;1&#xff09;显示坐标&#xff1a; from torch.utils.tensorboard import SummaryWriter import numpy as np from PIL import Imagewriter SummaryWriter("logs") # 写入的位置 log_dir logs # writer.add_image() "…

【LeetCode: 148. 排序链表 + 链表 + 归并排序】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

今天来看看工商业储能收益模式有哪些

安科瑞武陈燕acrelcy 2023 年有望成为工商业储能的发展元年&#xff0c;主要原因2023年工商业储能的经济性有望大幅提升。工商业储能下游主要为工商业企业&#xff0c;投资是否具有经济性是工商业需求的核心因素之一&#xff0c;而2023年工商业储能经济性或将显著提升&#xf…