智能指针基础知识【C++】【RAII思想 || unique_ptr || shared_ptrweak_ptr || 循环引用问题】
目录
一,为什么需要智能指针
二,内存泄露的基本认识
1. 内存泄露分类
2. 常见的内存检测工具
3,如何避免内存泄露
三,智能指针的使用与原理
1. RAII思想
2. 智能指针
(1. unique_ptr
3. weak_ptr解决循环引用问题
4. 定制删除器(了解)
嗨!收到一张超美的风景图,愿你每天都能顺心!

一,为什么需要智能指针
假设我们调用func函数,我们会发现:div函数操作,如果抛异常,则p1, p2就不会释放导致内存泄露。
void Func (){// 1 、如果 p1 这里 new 抛异常会如何?// 2 、如果 p2 这里 new 抛异常会如何?// 3 、如果 div 调用这里又会抛异常会如何?int* p1 = new int ;int* p2 = new int ;cout << div () << endl ;delete p1 ;delete p2 ;}
二,内存泄露的基本认识
1. 内存泄露分类
2. 常见的内存检测工具
在linux下内存泄漏检测: Linux下几款C++程序中的内存泄露检查工具_c++内存泄露工具分析-CSDN博客
在windows下使用第三方工具 : VS编程内存泄漏:VLD(Visual LeakDetector)内存泄露库_visual leak detector vs2020-CSDN博客
其他工具: 内存泄露检测工具比较 - 默默淡然 - 博客园 (cnblogs.com)
3,如何避免内存泄露
三,智能指针的使用与原理
1. RAII思想
- 不需要显式地释放资源。
- 采用这种方式,对象所需的资源在其生命期内始终保持有效。
// 使用RAII思想设计的SmartPtr类
template<class T>
class SmartPtr {
public:SmartPtr(T* ptr = nullptr): _ptr(ptr){}~SmartPtr(){if(_ptr)delete _ptr;}private:T* _ptr;
};
int div(){int a, b;cin >> a >> b;if (b == 0)throw invalid_argument("除0错误");return a / b;}
void Func()
{ShardPtr<int> sp1(new int);ShardPtr<int> sp2(new int);cout << div() << endl;
}
int main()
{try {Func();}catch(const exception& e){cout<<e.what()<<endl;}return 0;
}
2. 智能指针
所以,基本的框架就有了:
// 功能像指针一样
template <class T>
class SmartPtr
{
public:SmartPtr(T* ptr):_ptr(ptr){}~SmartPtr(){delete _ptr;}T& operator*(){return *_ptr;}T* operator->(){return &(*_ptr);}
private:T* _ptr;
};
这只是初步的框架,我们知道这个SmartPtr类的拷贝构造是浅拷贝。如果两个该类对象指向同一个内容,在析构时将会析构两次,进而出现报错。换个方向,这个类类似我们学习的迭代器,但我们当时没有考虑析构的问题?
答:迭代器只是管理数据的机构,数据析构是数据本身的事情。
说到拷贝,我们要认识智能指针的发展史:

C++98的不好用,在C++11中引入了unique_ptr, shared_ptr&weak_ptr,他们两来自Boost库 。
Boost的准标准库(标准库就是C++编译器就支持的,准标准库需要外部引入源码库的),怎么理解Boost? 可以理解为标准库的体验服。
(1. unique_ptr
主旨:简单粗暴禁止拷贝。(auto_ptr栽在拷贝上)
方法一:将构造函数声明并放入private区中,这样外部无法定义访问。

方法二:强制禁用

(2. shared_ptr & weak_ptr
玩法:引用计数,并且支持拷贝
1. shared_ptr在其内部, 给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享。2. 在 对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减一。3. 如果引用计数是0,就说明自己是最后一个使用该资源的对象, 必须释放该资源;4. 如果不是0,就说明除了自己还有其他对象在使用该份资源, 不能释放该资源,否则其他对象就成野指针了。

下面是简单模拟实现的shared_ptr:
template <class T>
class share_ptr
{
public:share_ptr(T* ptr):_ptr(ptr),_pcount(new int(1)),_mtx(new mutex){}~share_ptr(){destory();}void destory(){_mtx->lock();bool flag = false;if (--(*_pcount) == 0){cout << " delete :" << *_ptr << endl;delete _ptr;delete _pcount;flag = true;}_mtx->unlock();if (flag == true){delete _mtx;}}void AddCount(const share_ptr<T>& it){_mtx->lock();(*it._pcount)++;_mtx->unlock();}T& operator*(){return *_ptr;}T* operator->(){return &(*_ptr);}share_ptr(const share_ptr<T>& it):_ptr(it._ptr),_pcount(it._pcount),_mtx(it._mtx){AddCount(it);}share_ptr<T>& operator=(const share_ptr<T>& it){// 防止自己赋值自己导致数据丢失if (_ptr != it._ptr){destory();_ptr = it._ptr;_mtx = it._mtx;_pcount = it._pcount;AddCount(it); // 计数++return *this;}}
private:T* _ptr;int* _pcount;mutex* _mtx;
};
shared_ptr的循环引用问题
特征:互相使用shared_ptr指向对方, 且双方有第三者指向
struct ListNode
{
int _data;
shared_ptr<ListNode> _prev;
shared_ptr<ListNode> _next;
~ListNode() { cout << "~ListNode()" << endl; }
};int main()
{
shared_ptr<ListNode> node1(new ListNode);
shared_ptr<ListNode> node2(new ListNode);
cout << node1.use_count() << " "; // 打印链接数
cout << node2.use_count() << endl;
node1->_next = node2;
node2->_prev = node1;
cout << node1.use_count() << " ";
cout << node2.use_count() << endl;
return 0;}

3. weak_ptr解决循环引用问题
特征:
1. 不支持RAII思想
2. 像指针
3. 专门用来辅助shared_ptr,可以指向资源,但不管理资源,也不增加计数。
// 简化版本的weak_ptr实现
template<class T>
class weak_ptr
{
public:weak_ptr():_ptr(nullptr){}weak_ptr(const shared_ptr<T>& sp):_ptr(sp.get()){}weak_ptr<T>& operator=(const share_ptr<T>& sp){_ptr = sp.get();return *this;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}
private:T* _ptr;
};

4. 定制删除器(了解)
我们注意到,我们的析构函数底层都是delete,但对象是数组,文件指针,delete析构就不合适,所以我们的shared_ptr有了定制删除器的用法。

本质上就是类似仿函数,下面是几个使用案例:
template <class T>
struct DeleteArray
{void operator()(T* ptr){if (ptr != nullptr){delete[] ptr;}}
};
int main()
{// 自己写仿函数法shared_ptr<Date> pt1(new Date[10], DeleteArray<Date>());// 函数指针法这个过于简单的就不做演示// lambda法shared_ptr<Date> pt2(new Date[100], [](Date* ptr) { delete[] ptr; });// function对象法shared_ptr<Date> pt3(new Date[1000], function<void(Date*)> (DeleteArray<Date>()));// 文件管理shared_ptr<FILE> pt4(fopen("test.txt", "r"), [](FILE* ptr) { fclose(ptr); });cout << "endl";return 0;
}
结语
本小节就到这里了,感谢小伙伴的浏览,如果有什么建议,欢迎在评论区评论,如果给小伙伴带来一些收获请留下你的小赞,你的点赞和关注将会成为博主创作的动力。
相关文章:
智能指针基础知识【C++】【RAII思想 || unique_ptr || shared_ptrweak_ptr || 循环引用问题】
目录 一,为什么需要智能指针 二,内存泄露的基本认识 1. 内存泄露分类 2. 常见的内存检测工具 3,如何避免内存泄露 三,智能指针的使用与原理 1. RAII思想 2. 智能指针 (1. unique_ptr (2. shared_…...
leetcode:反转链表II 和k个一组反转链表的C++实现
反转链表II 问题描述 给你单链表的头指针 head 和两个整数 left 和 right ,其中 left < right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。 ListNode* reverseBetween(ListNode* head, int left, int right) {ListNode *…...
ERD Online 快速启动指南:代码下载到首次运行的全流程攻略 ️
🚀 一、代码下载 ERD online前端代码正常拉取即可👌 后端代码含有子模块,拉取命令如下: git clone --recurse-submodules https://github.com/www-zerocode-net-cn/martin-framework.git 🛠️ 二、代码构建 dz…...
c++ 11 新特性 不同数据类型之间转换函数之const_cast
一.不同数据类型之间转换函数const_cast介绍 const_cast是C11中引入的一种类型转换操作符,用于修改类型的const或volatile属性。const_cast的主要用途是移除对象的常量性,它是唯一具有此能力的C风格的转型操作符。在C11中,const_cast可以完成…...
C++从零开始的打怪升级之路(day45)
这是关于一个普通双非本科大一学生的C的学习记录贴 在此前,我学了一点点C语言还有简单的数据结构,如果有小伙伴想和我一起学习的,可以私信我交流分享学习资料 那么开启正题 今天分享的是关于二叉树的题目 1.根据二叉树创建字符串 606. 根…...
小鹅通前端实习一面
总时长35分钟,自我介绍开始 1.js和c特点上的差异; 2.js数组去重 3.js的数据类型 4.js的引用类型和值类型的差别 5.讲一下js的网络请求 6.对前端三件套和框架的理解 7.一个html文档的结构是怎样的 8.head和body的区别 9.一个页面的加载顺序(ht…...
ArrayList常用API
常见方法 add 增remove 删set 改get 查clear 清空元素size 长度isEmpty 为空判断 用法 // String就是泛型 这种使用方法对于限制类型很有用 ArrayList<String> arrayList new ArrayList<>();// add 添加元素 返回的是boolean 代表是否添加成功 arrayList.add(&qu…...
Chrome安装Axure插件
打开原型目录/resources/chrome,重命名axure-chrome-extension.crx,修改后缀为rar,axure-chrome-extension.rar 解压到axure-chrome-extension目录打开Chrome,更多工具->扩展程序,打开开发者模式,选择加…...
【AI+应用】模仿爆款视频二次创作短视频操作步骤
本来不想水这篇的, 剪辑软件估计很多人用的比我还6。 今天自己遇到1个需求,我看到一篇公众号文章的视频觉得有意思,但视频有点长,我没带耳机看视频的习惯,就想着能不能下载下来, 提取视频的音频转为文字&am…...
HTML使用
文章目录 一、简介二、HTML快速入门三、基础标签四、图片、音频、视频标签五、超链接标签六、列表标签七、表格标签八、布局标签九、表单标签十、表单向标签 一、简介 二、HTML快速入门 <html><head><title>你好</title></head><body>再…...
通过联合部署DDoS高防和WAF提升网站防护能力
如果您的网站遭受的攻击既有流量型攻击,又混杂精巧的Web应用层攻击时(例如SQL注入、跨站脚本攻击、命令注入等)时,推荐您组合使用阿里云DDoS高防和Web 应用防火墙 WAF(Web Application Firewall)࿰…...
具体挫折现象的发生以及解法思考:您如果继续不问的话,严重重责就容易来
一 积极想方设法的寻找扭转劣势的方式方法; 目前对于第一条的践行,主要还是依靠打工做事赚取收入。至于个人业务,只能往后推,往后延迟。因为不管您目前居住的环境,还是个人条件都不行,所以无法实行个人业…...
Type-C接口PD协议统一:引领电子科技新纪元的优势解析
在电子科技日新月异的今天,充电接口的统一化已经成为了业界的一大趋势。其中,Type-C接口凭借其传输速度快、使用便捷等优点,迅速成为了市场上的主流选择。而PD(Power Delivery)协议的统一,更是为Type-C接口…...
探讨2024年AI辅助研发的趋势
一、引言 随着科技的飞速发展,人工智能(AI)已经成为当今时代最具变革性的技术之一。AI的广泛应用正在重塑各行各业,其中,AI辅助研发作为科技和工业领域的一大创新热点,正引领着研发模式的深刻变革。从医药…...
Java对接海康威视摄像头实现抓图
目录 一、下载SDK 二、拷贝示例代码 三、拷贝库文件 四、运行Demo 五、抓图业务 六、调参 七、发布Linux正式环境 一、下载SDK 海康开放平台 二、拷贝示例代码 三、拷贝库文件 这时候直接运行ClientDemo会报错,因为缺失库文件! 四、运行Demo …...
浏览器一键重新发起请求
一、需求场景 在前端开发过程中,经常会需要重新请求后台进行代码调试,之前的常规方法是刷新浏览器页面或者点击页面进行交互,这样对多个请求的场景就很方便,但是往往很多时候我们只是单纯的想重新发起一个请求(多个请求…...
一起来读李清照
当然先祝各位女生节日快乐🎁🎁啦。 但是呢,今天,我们不聊技术,来聊点其他的。 大家都知道今天是三八妇女节,三八妇女节的是中国人的叫法,也叫国际妇女节。是为了纪念妇女权利的运动&#…...
找出单身狗1,2
目录 1. 单身狗12. 单身狗2 1. 单身狗1 题目如下: 思路:一部分人可能会使用对数组排序,遍历数组的方式去找出只出现一次的数字,但这种方法的时间复杂度过高,有时候可能会不满足要求。 有一种十分简便的方法是使用异或…...
贝叶斯优化BiLSTM分类预测(matlab代码)
贝叶斯优化BiLSTM分类matlab代码 数据为Excel分类数据集数据。 数据集划分为训练集、验证集、测试集,比例为8:1:1 数据处理: 在数据加载后,对数据进行了划分,包括训练集、验证集和测试集,这有助于评估模型的泛化能力。 数据标…...
Linux运维:实现光盘开机自动挂载、配置本地yum源教程
Linux运维:实现光盘开机自动挂载、配置本地yum源教程 一、光盘开机自动挂载1、检查光驱设备2、创建挂载点3、编辑/etc/fstab文件4、测试挂载 二、配置本地yum源(挂载光盘或ISO文件)1、挂载ISO文件2、创建YUM仓库配置文件3、清理YUM缓存并测试 💖The Begi…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
