智能指针中的weak_ptr(弱引用智能指针)
弱引用智能指针 std::weak_ptr 可以看做是shared_ptr的助手,它不管理 shared_ptr 内部的指针。std::weak_ptr 没有重载操作符*和->,因为它不共享指针,
不能操作资源,所以它的构造不会增加引用计数,析构也不会减少引用计数,它的主要作用就是作为一个旁观者监视shared_ptr 中管理的资源是否存在.
初始化
#include<iostream>
#include<memory>
using namespace std;int main(){shared_ptr<int> sp(new int);//weak_ptr<int> wp1;//空weak_ptr对象weak_ptr<int> wp2(wp1);//也是空weak_ptr<int> wp3(sp);//通过shared_ptr对象构造一个可用的weak_ptr实例对象,就是wp3监管spweak_ptr<int> wp4;wp4=sp;//通过shared_ptr对象构造一个可用的weak_ptr实例对象(这是一个隐式类型转换),给赋值运算符重载了weak_ptr<int> wp5;wp5=wp3;//通过weak_ptr对象构造一个可用的weak_ptr实例对象,给赋值运算符重载了
}
use_count()
通过调用weak_ptr类提供的use_count()方法可以获得当前观测资源的引用计数
#include<iostream>
#include<memory>
using namespace std;
int main() {
shared_ptr<int> sp(new int);
weak_ptr<int> wp1;
weak_ptr<int> wp2(wp1);
weak_ptr<int> wp3(sp);
weak_ptr<int> wp4;
wp4 = sp;
weak_ptr<int> wp5;
wp5 = wp3;
cout << wp1.use_count() << endl;
cout << wp2.use_count() << endl;
cout << wp3.use_count() << endl;
cout << wp4.use_count() << endl;
cout << wp5.use_count() << endl;
}/*运行结果:
0
0
1
1
1*/
通过打印的结果可以知道,虽然弱引用智能指针 wp3、wp4、wp5 监测的资源是同一个,但是它的引用计数并没有发生任何的变化,也进一步证明了 weak_ptr 只是监测资源,并不管理资源。
expired()(失效的)
通过调用 std::weak_ptr 类提供的 expired()方法来判断观测的资源是否已经被释放
#include<iostream>
#include<memory>
using namespace std;
int main() {
shared_ptr<int> shared(new int(10));
weak_ptr<int> weak(shared);
cout << weak.expired() << endl;
shared.reset();
cout << weak.expired() << endl;return 0;
}
/*运行结果:
0
1*/
weak_ptr监测的就是shared_ptr管理的资源,当共享智能指针调用 shared.reset();之后管理的资源被释放,因此 weak.expired()函数的结果返回 true,表示监测的资源已经不存在了。
lock()
通过调用weak_ptr类提供的lock()方法来获取管理所监测资源的shared_ptr对象
#include<iostream>
#include<memory>
using namespace std;
int main() {
shared_ptr<int> sp1, sp2;
weak_ptr<int> wp;
sp1 = make_shared<int>(520);
wp = sp1;
sp2 = wp.lock();
cout << wp.use_count() << endl;
sp1.reset();
cout << wp.use_count() << endl;
sp1 = wp.lock();
cout << wp.use_count() << endl;cout << *sp1 << endl;
cout << *sp2 << endl;return 0;
}/*运行结果:
2
1
2
520
520*/
sp2 = wp.lock();通过调用 lock()方法得到一个用于管理 weak_ptr 对象所监测的资源的共享智能指针对象,使用这个对象初始化 sp2,此时所监测资源的引用计数为 2.
sp1.reset();共亨智能指针 sp1 被重置,weak_ptr 对象所监测的资源的引用计数减 1
sp1 = wp.lock();sp1 重新被初始化,并且管理的还是 weak_ptr 对象所监测的资源,因此引用计数加 1.
共享智能指针对象 sp1 和 sp2 管理的是同一块内存,因此最终打印的内存中的结果是相同的,都是 520.
reset()
通过调用 std::weak_ptr 类提供的 reset()方法来清空对象,使其不监测任何资源。
#include<iostream>
#include<memory>
using namespace std;
int main() {
shared_ptr<int> sp(new int(10));
weak_ptr<int> wp(sp);
cout << wp.expired() << endl;
wp.reset();
cout << wp.expired() << endl;
cout << sp.use_count() << endl;return 0;
}/*运行结果:
0
1
1*/
返回管理this的shared_ptr
#include<iostream>
#include<memory>
using namespace std;struct Test
{shared_ptr<Test> getSharedPtr(){return shared_ptr<Test>(this); }~Test(){cout<<"析构函数"<<endl; }
};
int main()
{shared_ptr<Test> sp1(new Test);cout<<"引用个数"<<sp1.use_count()<<endl;shared_ptr<Test> sp2=sp1->getSharedPtr();cout<<"引用个数"<<sp1.use_count()<<endl;return 0;
}
当用Test的对象初始化sp1时,sp1指向这个对象,当sp1调用getSharedPtr函数时,要给隐含参数this传值,传的就是Test对象的原始地址,这就会导致用原始地址初始化多次智能指针,这俩智能指针各自维护着自己的引用计数,当一个引用计数为0时,就会释放那块空间,而另一个指针不知道那块空间被释放,会再次释放那块空间,导致二次释放问题
通过输出的结果可以看到一个对象被析构了两次,其原因是这样的:在这个例子中使用同一个指针 this 构造了两个智能指针对象 sp1 和 sp2,这二者之间是没有任何关系的,因为 sp2 并不是通过 sp1 初始化得到的实例对象。在离开作用域之后 this 将被构造的两个智能指针各自析构导致重复析构的错误。
循环引用
#include<iostream>
#include<memory>
using namespace std;class A;
class B;
class A{
public:shared_ptr<B> bptr;~A(){cout<<"A的析构"<<endl; }
};
class B{
public:shared_ptr<A> aptr;~B(){cout<<"B的析构"<<endl; }
};
void testPtr(){shared_ptr<A> ap(new A);shared_ptr<B> bp(new B);cout<<"A的引用计数:"<<ap.use_count()<<endl;cout<<"B的引用计数:"<<bp.use_count()<<endl;ap->bptr=bp;bp->aptr=ap;cout<<"A的引用计数:"<<ap.use_count()<<endl;cout<<"B的引用计数:"<<bp.use_count()<<endl;
}
int main(){testPtr();return 0;
}
当作用域结束,想要释放A对象,就得让A对象里面的bptr引用计数为0,但是aptr指向的是B,只有B没有,bptr引用计数才为0,但是B里有个aptr,只有aptr引用计数为0,B才能没,但是aptr指向的是A,只有A没了,aptr才能没,这就导致,两边都没不了,ap和bp引用计数都不为0
要解决这个循环引用问题,可以考虑使用weak_ptr(弱指针)来打破循环引用,例如将类A中的shared_ptr改为weak_ptr,类B中的shared_ptr改为weak_ptr,这样就可以在需要访问对方对象时通过weak_ptr的lock方法来获取有效的shared_ptr,同时又不会造成循环引用导致的析构函数无法调用的问题。
相关文章:
智能指针中的weak_ptr(弱引用智能指针)
弱引用智能指针 std::weak_ptr 可以看做是shared_ptr的助手,它不管理 shared_ptr 内部的指针。std::weak_ptr 没有重载操作符*和->,因为它不共享指针, 不能操作资源,所以它的构造不会增加引用计数,析构也不会减少引用计数,它的…...

【电子通识】机电继电器和固态继电器的区别
机电继电器 机电继电器于19世纪中叶发明。这些器件将线圈与可移动的金属触点结合使用来充当电动开关。这些器件会因为金属触点出现磨损而发生故障,例如焊死在一起。因此,在完全失效之前器件能够进行的开关周期数有限,从而限制了其总体可靠性。 一般情况下继电器控制…...

工业异常检测-CVPR2024-新的3D异常数据合成办法和自监督网络IMRNet
论文:https://arxiv.org/pdf/2311.14897v3.pdf 项目:https://github.com/chopper-233/anomaly-shapenet 这篇论文主要关注的是3D异常检测和定位,这是一个在工业质量检查中至关重要的任务。作者们提出了一种新的方法来合成3D异常数据&#x…...

如何创建对话窗口
文章目录 1. 概念介绍2. 使用方法3. 示例代码我们在上一章回中介绍了Dismissible Widget相关的内容,本章回中将介绍AlertDialog Widget.闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们介绍的AlertDialog是指程序中弹出的确认窗口,其实我们在上一章回中删除ListView中…...

新手上路,学Go还是Python
对于新手来说,Go和Python都是很好的编程语言,它们各有特点,以下是详细的对比来帮助你决定先学哪一个: 一、语法和学习难度 Python 语法简洁易懂:Python以其简洁、优雅的语法而闻名,代码的可读性很高。例如…...
<!DOCTYPE html>的作用是什么
一、背景 从今天开始会不定时的发布一些前端的常见面试题,供大家参考。今天要发布的内容是关于html的面试题的作用是什么。接下来就一起讨论以下吧 二、概念 DOCTYPE 是html5中一种标准通用标记语言的文档类型的声明,它的目的就是为了告诉浏览器应该以…...

EasyExcel改名为FastExce做了那些改变呢
回到:github原作者地址:https://github.com/CodePhiliaX/fastexcel 中文 |English | 什么是 FastExcel FastExcel 是由原 EasyExcel 作者创建的新项目。2023 年我已从阿里离职,近期阿里宣布停止更新 EasyExcel,作者他本人决定继…...

狗狗的生育周期:关注与呵护
狗狗的繁殖是一个复杂且需要谨慎对待的过程,了解其生产周期对于宠物主人以及从事相关行业的人员至关重要。 一般而言,狗狗的怀孕周期约为两个月左右,但这并非绝对固定。从受孕到分娩,通常在 58 至 65 天之间波动。小型犬可能相对…...

ABAP DIALOG屏幕编程2
在上一篇博客ABAP DIALOG屏幕编程1中阐述了DIALOG、PBO、PAI的概念并且对常用页面元素怎么用进行了演示。在这一篇博文中会讲述怎么添加下拉框、搜索帮助,怎么创建表控件、屏幕跳转等。会用到上一篇里面的内容。 有关程序包含文件结构如下。 一、响应用户指令 如上…...
获取缓存大小与清除 Web 缓存 - 鸿蒙 HarmonyOS Next
针对浏览器 Web 组件清除缓存相关,具体实现如下 code 实例所示: /*公共方法类*/ export class PublicUtils {/*获取缓存大小*/static async getCacheSize(): Promise<number> {try {let bundleStats await storageStatistics.getCurrentBundleStats()let size bundleS…...
在Unreal Engine中,UHT与反射机制
UHT(Unreal Header Tool) 是虚幻引擎(Unreal Engine)中的一个重要工具,它用于处理和生成引擎所需的元数据,使得虚幻引擎能够执行许多复杂的功能,如反射、序列化、蓝图交互、垃圾回收等。简而言之…...

SQL项目实战与综合应用——项目设计与需求分析
项目设计与需求分析是软件开发过程中的核心环节,尤其在涉及数据库的应用时,良好的设计将直接影响到项目的可扩展性、性能和维护性。本文将深入探讨数据库设计的最佳实践,结合 C 与 SQL 的实际应用场景,涵盖项目需求收集、数据库设…...
分布式中的CAP定理和BASE理论与强弱一致性
分布式中的CAP定理和BASE理论与强弱一致性 CAP定理 CAP定理,也称为布鲁尔定理(Brewer’s Theorem),是由加州大学伯克利分校的Eric Brewer教授在2000年提出的,并由麻省理工学院的Seth Gilbert和Nancy Lynch于2002年正…...
C/C++常见符号与运算符
C/C常见符号与运算符对照表 符号用法与意义与Java类比:在条件运算符中 (cond ? x : y) 表示条件为假的分支;在 switch-case 中如 case 1:表示标签结束点;在自定义标签如 label: 中用于 goto 跳转Java中? :三元运算相同;switch-case中也有:…...

了解 k8s 网络基础知识
了解 Docker 网络模式 在使用 Docker run 创建 Docker 容器时,可以使用 --net 选项指定容器的网络模式,Docker 可以有4种网络模式。 host 模式。–nethost 指定和宿主机共用一个 NetWork Namespace,容器中的网络环境(ip 地址、路…...

用户信息界面按钮禁用+发送消息功能
用户信息界面按钮禁用发送消息功能 前言 那么在上一集我们就完成了个人信息窗口所有的内容的修改,那么我们就需要进一步来看我们别的用户的信息界面的窗口。 需求分析 在之前的我们也讲了用户信息界面窗口一共有下图几种组件。 用户头像、用户id、用户昵称、用户…...

接近开关传感器-PCB线图电感式传感器【衰减系数1】
设计和工作原理 衰减系数为1的传感器是在电感式接近开关的基础上装备了特殊的振荡器。传感器内部有两个耦合空心线圈,能够保证根据不同的金属特性作合适的检测调整。无需考虑目标物是不同的金属,因为传感器能在同一感应距离下检测所有金属。 衰减系数为…...

C/C++流星雨
系列文章 序号直达链接1C/C爱心代码2C/C跳动的爱心3C/C李峋同款跳动的爱心代码4C/C满屏飘字表白代码5C/C大雪纷飞代码6C/C烟花代码7C/C黑客帝国同款字母雨8C/C樱花树代码9C/C奥特曼代码10C/C精美圣诞树11C/C俄罗斯方块12C/C贪吃蛇13C/C孤单又灿烂的神-鬼怪14C/C闪烁的爱心15C/C…...

计算机网络:传输层、应用层、网络安全、视频/音频/无线网络、下一代因特网
目录 (五)传输层 1.传输层寻址与端口 2.无连接服务与面向连接服务 3. 传输连接的建立与释放 4. UDP 的优点 5. UDP 和 TCP 报文段报头格式 6. TCP 的流量控制 7.TCP 的拥塞控制 8. TCP 传送连接的管理 &#…...
[漏洞挖掘与防护] 05.CVE-2018-12613:phpMyAdmin 4.8.1后台文件包含缺陷复现及防御措施
这是作者新开的一个专栏——“漏洞挖掘与防护”,前期会复现各种经典和最新漏洞,并总结防护技巧;后期尝试从零学习漏洞挖掘技术,包括Web漏洞和二进制及IOT相关漏洞,以及Fuzzing技术。新的征程,新的开启,漫漫长征路,偏向虎山行。享受过程,感谢您的陪伴,一起加油~ 欢迎关…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...

USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...

MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...