当前位置: 首页 > news >正文

智能指针基础知识【C++】【RAII思想 || unique_ptr || shared_ptrweak_ptr || 循环引用问题】

目录

一,为什么需要智能指针

二,内存泄露的基本认识

1. 内存泄露分类

2. 常见的内存检测工具

3,如何避免内存泄露

三,智能指针的使用与原理

1. RAII思想

2. 智能指针

(1. unique_ptr

(2. shared_ptr & weak_ptr

 shared_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. 内存泄露分类

C/C++程序中一般我们关心两种方面的内存泄漏:
堆内存泄漏(Heap leak)(本章关注点)
堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。

系统资源泄漏
指程序使用 系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。

2. 常见的内存检测工具

linux下内存泄漏检测: Linux下几款C++程序中的内存泄露检查工具_c++内存泄露工具分析-CSDN博客

windows下使用第三方工具 : VS编程内存泄漏:VLD(Visual LeakDetector)内存泄露库_visual leak detector vs2020-CSDN博客

其他工具: 内存泄露检测工具比较 - 默默淡然 - 博客园 (cnblogs.com)

3,如何避免内存泄露

1. 采用 RAII思想或者智能指针来管理资源。
2. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带 内存泄漏检测的功能选项。 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。
总结一下:
内存泄漏非常常见,解决方案分为两种:1、事前预防型,如 RAII思想,智能指针等。2、事后查错型,如 泄漏检测工具

三,智能指针的使用与原理

1. RAII思想

RAII(Resource Acquisition Is Initialization)是一种在 利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。 在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效, 最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:
  • 不需要显式地释放资源。
  • 采用这种方式,对象所需的资源在其生命期内始终保持有效。
如下面例子:
// 使用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. 智能指针

上述的SmartPtr之所以称为RAll思想,而不是智能指针,因为它还不具有指针的行为。指针可以解引用,也可以通过->去访问所指空间中的内容,因此: AutoPtr模板类中还得需要将* 、->重载下,才可让其像指针一样去使用

所以,基本的框架就有了:

// 功能像指针一样
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

玩法:引用计数,并且支持拷贝

shared_ptr的原理:是通过引用计数的方式来实现多个shared_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 || 循环引用问题】

目录 一&#xff0c;为什么需要智能指针 二&#xff0c;内存泄露的基本认识 1. 内存泄露分类 2. 常见的内存检测工具 3&#xff0c;如何避免内存泄露 三&#xff0c;智能指针的使用与原理 1. RAII思想 2. 智能指针 &#xff08;1. unique_ptr &#xff08;2. shared_…...

leetcode:反转链表II 和k个一组反转链表的C++实现

反转链表II 问题描述 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 ListNode* reverseBetween(ListNode* head, int left, int right) {ListNode *…...

ERD Online 快速启动指南:代码下载到首次运行的全流程攻略 ️

&#x1f680; 一、代码下载 ERD online前端代码正常拉取即可&#x1f44c; 后端代码含有子模块&#xff0c;拉取命令如下&#xff1a; git clone --recurse-submodules https://github.com/www-zerocode-net-cn/martin-framework.git &#x1f6e0;️ 二、代码构建 &#x1f3…...

c++ 11 新特性 不同数据类型之间转换函数之const_cast

一.不同数据类型之间转换函数const_cast介绍 const_cast是C11中引入的一种类型转换操作符&#xff0c;用于修改类型的const或volatile属性。const_cast的主要用途是移除对象的常量性&#xff0c;它是唯一具有此能力的C风格的转型操作符。在C11中&#xff0c;const_cast可以完成…...

C++从零开始的打怪升级之路(day45)

这是关于一个普通双非本科大一学生的C的学习记录贴 在此前&#xff0c;我学了一点点C语言还有简单的数据结构&#xff0c;如果有小伙伴想和我一起学习的&#xff0c;可以私信我交流分享学习资料 那么开启正题 今天分享的是关于二叉树的题目 1.根据二叉树创建字符串 606. 根…...

小鹅通前端实习一面

总时长35分钟&#xff0c;自我介绍开始 1.js和c特点上的差异&#xff1b; 2.js数组去重 3.js的数据类型 4.js的引用类型和值类型的差别 5.讲一下js的网络请求 6.对前端三件套和框架的理解 7.一个html文档的结构是怎样的 8.head和body的区别 9.一个页面的加载顺序&#xff08;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&#xff0c;重命名axure-chrome-extension.crx&#xff0c;修改后缀为rar&#xff0c;axure-chrome-extension.rar 解压到axure-chrome-extension目录打开Chrome&#xff0c;更多工具->扩展程序&#xff0c;打开开发者模式&#xff0c;选择加…...

【AI+应用】模仿爆款视频二次创作短视频操作步骤

本来不想水这篇的&#xff0c; 剪辑软件估计很多人用的比我还6。 今天自己遇到1个需求&#xff0c;我看到一篇公众号文章的视频觉得有意思&#xff0c;但视频有点长&#xff0c;我没带耳机看视频的习惯&#xff0c;就想着能不能下载下来&#xff0c; 提取视频的音频转为文字&am…...

HTML使用

文章目录 一、简介二、HTML快速入门三、基础标签四、图片、音频、视频标签五、超链接标签六、列表标签七、表格标签八、布局标签九、表单标签十、表单向标签 一、简介 二、HTML快速入门 ​ <html><head><title>你好</title></head><body>再…...

通过联合部署DDoS高防和WAF提升网站防护能力

如果您的网站遭受的攻击既有流量型攻击&#xff0c;又混杂精巧的Web应用层攻击时&#xff08;例如SQL注入、跨站脚本攻击、命令注入等&#xff09;时&#xff0c;推荐您组合使用阿里云DDoS高防和Web 应用防火墙 WAF&#xff08;Web Application Firewall&#xff09;&#xff0…...

具体挫折现象的发生以及解法思考:您如果继续不问的话,严重重责就容易来

一 积极想方设法的寻找扭转劣势的方式方法&#xff1b;  目前对于第一条的践行&#xff0c;主要还是依靠打工做事赚取收入。至于个人业务&#xff0c;只能往后推&#xff0c;往后延迟。因为不管您目前居住的环境&#xff0c;还是个人条件都不行&#xff0c;所以无法实行个人业…...

Type-C接口PD协议统一:引领电子科技新纪元的优势解析

在电子科技日新月异的今天&#xff0c;充电接口的统一化已经成为了业界的一大趋势。其中&#xff0c;Type-C接口凭借其传输速度快、使用便捷等优点&#xff0c;迅速成为了市场上的主流选择。而PD&#xff08;Power Delivery&#xff09;协议的统一&#xff0c;更是为Type-C接口…...

探讨2024年AI辅助研发的趋势

一、引言 随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已经成为当今时代最具变革性的技术之一。AI的广泛应用正在重塑各行各业&#xff0c;其中&#xff0c;AI辅助研发作为科技和工业领域的一大创新热点&#xff0c;正引领着研发模式的深刻变革。从医药…...

Java对接海康威视摄像头实现抓图

目录 一、下载SDK 二、拷贝示例代码 三、拷贝库文件 四、运行Demo 五、抓图业务 六、调参 ​七、发布Linux正式环境 一、下载SDK 海康开放平台 二、拷贝示例代码 三、拷贝库文件 这时候直接运行ClientDemo会报错&#xff0c;因为缺失库文件&#xff01; 四、运行Demo …...

浏览器一键重新发起请求

一、需求场景 在前端开发过程中&#xff0c;经常会需要重新请求后台进行代码调试&#xff0c;之前的常规方法是刷新浏览器页面或者点击页面进行交互&#xff0c;这样对多个请求的场景就很方便&#xff0c;但是往往很多时候我们只是单纯的想重新发起一个请求&#xff08;多个请求…...

一起来读李清照

当然先祝各位女生节日快乐&#x1f381;&#x1f381;啦​。​ 但是呢&#xff0c;今天&#xff0c;我们不聊技术&#xff0c;来聊点其他的。 大家都知道今天是三八妇女节&#xff0c;三八妇女节的是中国人的叫法&#xff0c;也叫国际妇女节。是为了纪念妇女权利的运动&#…...

找出单身狗1,2

目录 1. 单身狗12. 单身狗2 1. 单身狗1 题目如下&#xff1a; 思路&#xff1a;一部分人可能会使用对数组排序&#xff0c;遍历数组的方式去找出只出现一次的数字&#xff0c;但这种方法的时间复杂度过高&#xff0c;有时候可能会不满足要求。 有一种十分简便的方法是使用异或…...

贝叶斯优化BiLSTM分类预测(matlab代码)

贝叶斯优化BiLSTM分类matlab代码 数据为Excel分类数据集数据。 数据集划分为训练集、验证集、测试集&#xff0c;比例为8:1:1 数据处理: 在数据加载后&#xff0c;对数据进行了划分&#xff0c;包括训练集、验证集和测试集&#xff0c;这有助于评估模型的泛化能力。 数据标…...

Linux运维:实现光盘开机自动挂载、配置本地yum源教程

Linux运维&#xff1a;实现光盘开机自动挂载、配置本地yum源教程 一、光盘开机自动挂载1、检查光驱设备2、创建挂载点3、编辑/etc/fstab文件4、测试挂载 二、配置本地yum源(挂载光盘或ISO文件)1、挂载ISO文件2、创建YUM仓库配置文件3、清理YUM缓存并测试 &#x1f496;The Begi…...

C语言从入门到精通 第十二章(程序的编译及链接)

写在前面&#xff1a; 本系列专栏主要介绍C语言的相关知识&#xff0c;思路以下面的参考链接教程为主&#xff0c;大部分笔记也出自该教程。除了参考下面的链接教程以外&#xff0c;笔者还参考了其它的一些C语言教材&#xff0c;笔者认为重要的部分大多都会用粗体标注&#xf…...

即插即用篇 | YOLOv8 引入 ParNetAttention 注意力机制 | 《NON-DEEP NETWORKS》

论文名称:《NON-DEEP NETWORKS》 论文地址:https://arxiv.org/pdf/2110.07641.pdf 代码地址:https://github.com/imankgoyal/NonDeepNetworks 文章目录 1 原理2 源代码3 添加方式4 模型 yaml 文件template-backbone.yamltemplate-small.yamltemplate-large.yaml...

基于51单片机的数字频率计设计

基于51单片机的数字频率计设计 摘要: 本文深入探讨了基于51单片机的数字频率计设计方案与实践。该设计方案不仅实现了对输入信号频率的高精度测量,还通过直观的数字显示提供了便捷的读取方式。在电子测量领域,频率作为核心参数之一,其准确测量对于确保通信、音频处理、控…...

20240307-1-前端开发校招面试问题整理JavaScript

前端开发校招面试问题整理【1】——JavaScript 1、JavaScript 基础 Q&#xff1a;介绍 js 的基本数据类型&#xff1f; 基本类型&#xff08;值类型&#xff09;&#xff1a;String&#xff0c;Number&#xff0c;Boolean&#xff0c;Null&#xff0c;Undefined&#xff0c;S…...

1.3 数据库系统的结构

目录 1.3.1 数据库系统模式的概念 1.3.2 数据库系统的三级模式结构 1. 模式 2. 外模式 3.内模式&#xff08;也称存储模式&#xff09; 1.3.3 数据库的二级映像功能与数据独立性 1.外模式&#xff0f;模式映像 2.模式&#xff0f;内模式映像 1.3.4 总结 模式 内模式…...

【Springer出版 · EI检索】| 第二届先进无人飞行系统国际会议(ICAUAS 2024)

会议简介 Brief Introduction 2024年第二届先进无人飞行系统国际会议(ICAUAS 2024) 会议时间&#xff1a;2024年6月14日-16日 召开地点&#xff1a;中国南昌 大会官网&#xff1a;ICAUAS 2024-2024 2nd International Conference on Advanced Unmanned Aerial Systems2024 2nd …...

RocketMQ快速入门_2. rocketmq 的应用场景、与其他mq的差异

0. 引言 之前我们讲解过rabbitMQ&#xff0c;本期我们将进入吞吐量更加强大的rocketMQ的学习。 1. 基础概念 如果你是刚接触MQ的同学&#xff0c;还不清楚消息队列的基础概念的&#xff0c;可以参考我之前这篇文章&#xff1a; https://wu55555.blog.csdn.net/article/deta…...

【Azure 架构师学习笔记】- Azure Private Endpoint

本文属于【Azure 架构师学习笔记】系列。 前言 公有云的其中一个特点是默认允许公网访问&#xff0c; 这就对企业环境带来风险&#xff0c;也是很多年前企业对公有云抵触的其中一个原因&#xff0c;现在这类问题已经很少&#xff0c;因为有了很多技术来确保云上的资源被安全地…...

开发知识点-Python-爬虫

爬虫 scrapybeautifulsoupfind_all find祖先/父节点兄弟节点nextpreviousCSS选择器属性值 attrsselect 后 class 正则使用字符串来描述、匹配一系列符合某个规则的字符串组成元字符使用grep匹配正则组与捕获断言与标记条件匹配正则表达式的标志 特定中文 匹配 scrapy scrapy内…...

如何修复eutil.dll文件,eutil.dll下载安装教程

在我们使用计算机的时候&#xff0c;偶尔会遭遇一些技术问题&#xff0c;其中一个比较常见的问题就是出现了"丢失eutil.dll文件"的提示。当我们的电脑告诉我们缺少了eutil.dll文件时&#xff0c;常常是因为某些程序无法找到这个文件而导致了程序的运行异常。那我们应…...