智能指针基础知识【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…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
