C++RAII内存管理技术

news2024/10/6 4:07:42

在这里插入图片描述

文章目录

  • 一.什么是RAII内存管理技术?
  • 二.智能指针
    • unique_ptr
    • shared_ptr
    • 循环引用问题
    • weak_ptr

一.什么是RAII内存管理技术?

  • C++在引入异常机制后,代码执行流的跳转变得难以预料,如果使用普通的指针进行内存管理,很难避免内存泄漏的问题(执行流跳转导致堆区资源无法被释放)
  • RAII技术指的是利用对象的生命周期来管理内存资源,就堆区内存资源的管理而言,指的就是:将指针封装在类中,在类对象构造时获取堆区资源,当类对象生命周期结束时,通过类对象的析构函数自动完成堆区资源的释放,这样的类对象就是智能指针
    • 智能指针可以有效地避免开发中出现内存泄漏的问题,同时为开发者省去了很多时间和精力

二.智能指针

  • C++11标准库中智能指针主要分为三大类:在这里插入图片描述

unique_ptr

  • unique_ptr对象之间不允许进行拷贝,即一个unique_ptr对象管理一块堆区内存资源,是一一对应的关系
  • unique_ptr的简单实现原理:
	//不允许拷贝的智能指针
	//delfunc是堆区资源释放函数,用于调用delete或者delete[]
	template<class T,class delfunc>
	class unique_ptr
	{
	public:
		unique_ptr(T * ptr = nullptr)
			:_ptr(ptr)
		{}

		~unique_ptr()
		{
			if (_ptr)
			{
				delfunc del;
				del(_ptr);
				std::cout << "delete" << std::endl;
			}
		}


		//让智能指针可以像指针一样被使用
		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}

		//禁止unique_ptr对象间的拷贝
		unique_ptr(const unique_ptr<T, delfunc>& unptr) = delete;
		unique_ptr<T, delfunc>& operator=(const unique_ptr<T, delfunc>& unptr) = delete;
	private:
		T* _ptr;
	};
  • 使用指针管理堆区资源时,我们会让其指向单个对象或者对象数组,单个对象delete完成资源释放,而对象数组要采用delete[]完成资源释放.unique_ptr的类模板参数delfunc的设计目的就是为了区分上述两种情况,让使用者通过设计仿函数的方式在deletedelete[]之间做选择

shared_ptr

  • shared_ptr是允许进行拷贝的智能指针,然而shared_ptr对象之间发生拷贝时,就会出现多个智能指针对象同时管理同一块堆区内存的情况,shared_ptr通过引用计数的技术避免了同一块堆区资源被释放多次的情况出现:在这里插入图片描述
  • 引用计数的实现思路:
    • shared_ptr内部封装一个指针int * recount用来维护引用计数变量
    • 每当一个shared_ptr对象进行构造并申请堆区资源时,同时在堆区申请一个int变量作为该shared_ptr对象所指向的堆区资源的引用计数变量
    • 每当shared_ptr被拷贝时,连同int * recount一起拷贝,然后让引用计数变量加一即可(赋值重载的实现还要考虑引用计数变量减一和堆区资源释放的问题)
    • 每当shared_ptr析构时,引用计数变量减一,若引用计数变量减为0,则释放堆区资源在这里插入图片描述
  • shared_ptr的简单实现原理:
    //允许拷贝的智能指针,利用引用计数解决内存管理冲突
	//delfunc是堆区资源释放函数,用于调用delete或者delete[]
	template<class T, class delfunc>
	class shared_ptr
	{
	public:
		//构造智能指针(同时创建引用计数变量)
		shared_ptr(T* ptr = nullptr)
			:_ptr(ptr),
			 _recount(new int(1))
		{}
		shared_ptr(const shared_ptr<T, delfunc>& shptr)
			: _ptr(shptr._ptr),
			  _recount(shptr._recount)
		{
			//智能指针拷贝增加引用计数
			(*_recount)++;
		}
		shared_ptr<T, delfunc>& operator=(const shared_ptr<T, delfunc>& shptr)
		{
			if (_ptr != shptr._ptr)
			{
				//智能指针指向改变,其先前指向的堆区内存和引用计数变量需要处理
				Release();
				//完成智能指针拷贝并增加引用计数
				_ptr = shptr._ptr;
				_recount = shptr._recount;
				++(*_recount);
			}
			return (*this);
		}
		~shared_ptr()
		{
			Release();
		}


		//让智能指针可以像指针一样被使用
		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}
		T* getptr() const
		{
			return _ptr;
		}
	private:
		//将资源释放函数进行封装,方便复用
		//引用计数减一,若引用计数减为0则释放资源
		void Release()
		{
			//引用计数减一
			--(*_recount);
			//引用计数为0则释放资源
			if (*_recount == 0)
			{
				if (_ptr)
				{
					delfunc del;
					del(_ptr);
					std::cout << "delete" << std::endl;
				}
				//同时注意释放引用计数变量
				delete _recount;
			}
		}
	private:
		T* _ptr;
		int* _recount;
	};
  • shared_ptr类内部同时还要解决引用计数变量带来的线程安全的问题,这里暂不讨论

循环引用问题

  • shared_ptr用在自引用结构体中会出现对象无法析构的问题:

template<class T>
class deletefunc
{
public:
	void operator()(T* ptr)
	{
		delete  ptr;
	}
};
// 循环引用
struct ListNode
{
	int _val;
	shared_ptr<ListNode,deletefunc<ListNode>> _next;
	shared_ptr<ListNode,deletefunc<ListNode>> _prev;
	~ListNode()
	{
		cout << "~ListNode()" << endl;
	}
};

// 循环引用
void test_shared_cycle()
{
	share_ptr<ListNode, deletefunc<ListNode>> n1(new ListNode);
	share_ptr<ListNode, deletefunc<ListNode>> n2(new ListNode);
	n1->_next = n2;
	n2->_prev = n1;
}
  • test_shared_cycle()函数执行完后,两个链表节点都无法正常析构,shared_ptr引发了循环引用的问题:在这里插入图片描述
  • n1节点的析构依赖于n2节点中_prev指针的析构,n2节点中_prev指针的析构依赖于n2节点的析构,n2节点的析构又依赖于n1节点中_next指针的析构, n1节点中_next指针的析构又依赖于n1节点的析构.如此往复构成了循环的依赖关系导致两个节点都无法被释放.
  • weak_ptr就是为了解决循环引用问题而设计的

weak_ptr

  • weak_ptr智能指针不参与堆区内存的申请和释放,也不会增加特定内存块的引用计数(其功能和普通指针差不多),weak_ptr支持以shared_ptr为引用形参的拷贝构造和赋值
  • weak_ptr简单实现原理:
	//用于配合share_ptr的使用用于循环引用的场景
	//delfunc是堆区资源释放函数,用于调用delete或者delete[]
	//weak_ptr不参与资源的申请和释放
	template<class T, class delfunc>
	class weak_ptr
	{
	public:
		weak_ptr()
			:_ptr(nullptr)
		{}

		~weak_ptr()
		{}
		
		weak_ptr(const weak_ptr<T, delfunc>& wptr)
			:_ptr(wptr._ptr)
		{}
		weak_ptr(const share_ptr<T, delfunc>& shptr)
			:_ptr(shptr.getptr())
		{}
		weak_ptr<T, delfunc>& operator=(const weak_ptr<T, delfunc>& wptr)
		{
			_ptr = wptr._ptr;
			return (*this);
		}
		weak_ptr<T, delfunc>& operator=(const share_ptr<T, delfunc>& shptr)
		{
			_ptr = shptr.getptr();
			return (*this);
		}

		//让智能指针可以像指针一样被使用
		T& operator*()
		{
			return *_ptr;
		}

		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};
  • 自引用结构体中采用weak_ptr就可以避免出现循环引用的问题
    在这里插入图片描述

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

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

相关文章

kafka集成篇

kafka的Java客户端 生产者 1.引入依赖 <dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-clients</artifactId><version>2.6.3</version></dependency>2.生产者发送消息的基本实现 /*** 消息的发送⽅*/ …

【 BERTopic应用 01/3】 分析卡塔尔世界杯推特数据

摄影&#xff1a; Rhett Lewis在 Unsplash上 一、说明 卡塔尔世界杯充满了惊喜&#xff01;从沙特阿拉伯通过击败阿根廷震惊世界到摩洛哥历史性地进入半决赛&#xff0c;你必须听到或见证那些足球热潮中的时刻。在这篇文章中&#xff0c;我将使用 BERTopic 来分析 2022 年世界杯…

ubuntu配置Android编译环境

本来以为把AndroidSDK下载到对应的位置上&#xff0c;直接用就行了&#xff0c;没想到编译的时候提示 说明自己下载的build-tools不行&#xff0c;没有同意过授权&#xff0c;还不能用。 正确的方式是怎样的呢&#xff0c;首先下载linux系统上运行的commandlinetools&#xff…

ROS2 学习(二)工作空间,节点

工作空间介绍 workspace 是存放整个项目的大目录。 其中包含&#xff1a; src&#xff1a;源码。 build&#xff1a;编译文件。 install&#xff1a;安装空间&#xff0c;存放编译成功后的目标文件。 log&#xff1a;日志。 我们新建一个工作空间目录&#xff0c;其中包…

Python自动化小技巧16——分类汇总写入excel不同sheet表

案例背景 上了两个月班的社畜博主最近终于有空来总结一下最近写的代码了。 因为上班都是文职工作&#xff0c;天天不是word就是excel就是PPT和pdf....这和什么机器学习还有数据科学不一样&#xff0c;任务更多的是处理实在的文字和表格等格式&#xff0c;按照领导要求来完成&…

【vue.js】手把手教你做一个会躲避鼠标指针的登录按钮

效果 背景 在登录的时候&#xff0c;我们都会做账号密码不可为空的验证&#xff0c;如何做出一个会躲避鼠标指针的登录按钮呢。废话不多说&#xff0c;3、2、1&#xff0c;上代码~ 代码 <!DOCTYPE html> <html lang"en" style"overflow: hidden;&qu…

ad+硬件每日学习十个知识点(34)23.8.14 (DCDC详细设计,续流二极管的选择,COMP引脚的环路设计)

文章目录 1.二极管的rrm电压和rms电压有什么不同2.DCDC续流二极管的选择3.充电电容4.COMP引脚的环路设计5.DCDC设计总结6.多路并联7.相位匹配8.工作模式9.低温输出偏离10.电源负载与效率11.降压升压模块 1.二极管的rrm电压和rms电压有什么不同 答&#xff1a; 二极管的 RRM &a…

JS_围绕圆形滑动

需求&#xff1a;滑动手势最大不能超过一个半径为50的圆形&#xff0c;超出围绕圆形边线滑动 这里只提供一个思路&#xff0c;下面代码可以运行&#xff0c;但是要使用需要改成自己的参数 <div style"width: 100%;height: 100vh;display: flex;justify-content: cente…

从雷军代码再上热搜给程序员们的启示

不久前&#xff0c;小米的一则关于雷军的宣传广告火了&#xff0c;这个宣传广告里隐藏了菜单&#xff0c;那些密密麻麻的字母就是雷军曾经写的代码&#xff0c;据小米公关部负责人王化表示&#xff0c;这张海报上的代码来自30年前&#xff0c;雷军在DOS环境下采用汇编语言亲自编…

Java鹰眼轨迹服务 轻骑小程序 运动健康与社交案例

Java地图专题课 基本API BMapGLLib 地图找房案例 MongoDB 百度地图鹰眼轨迹服务 鹰眼轨迹服务概述 鹰眼是一套轨迹管理服务&#xff0c;提供各端SDK和API供开发者便捷接入&#xff0c;追踪所管理的车辆/人员等运动物体。 基于鹰眼提供的接口和云端服务&#xff0c;开发者可以迅…

【 BERTopic应用 02/3】 分析卡塔尔世界杯推特数据

摄影&#xff1a;Fauzan Saari on Unsplash 一、说明 这是我们对世界杯推特数据分析的第3部分&#xff0c;我们放弃了。我们将对我们的数据进行情绪分析&#xff0c;以了解人们对卡塔尔世界杯的感受。我将在这里介绍的一个功能强大的工具包是Hugging Face&#xff0c;您可以在…

Mac鼠标增强工具Smooze Pro

Smooze Pro是一款Mac上的鼠标手势增强工具&#xff0c;可以让用户使用鼠标手势来控制应用程序和系统功能。 它支持多种手势操作&#xff0c;包括单指、双指、三指和四指手势&#xff0c;并且可以自定义每种手势的功能。例如&#xff0c;您可以使用单指向下滑动手势来启动Expos视…

el-table分页后序号连续的两种方法

实现效果&#xff1a; 第一页排序到10&#xff0c;第二页的排序应从11开始 实现方法一&#xff1a; 在el-table的序号列中使用template定义 <el-table><el-table-columnmin-width"10%"label"序号"><template slot-scope"scope"…

使用pymupdf实现PDF内容搜索并显示功能

简介&#xff1a; 在日常工作和学习中&#xff0c;我们可能需要查找和提取PDF文件中的特定内容。本文将介绍如何使用Python编程语言和wxPython图形用户界面库来实现一个简单的PDF内容搜索工具。我们将使用PyMuPDF模块来处理PDF文件&#xff0c;并结合wxPython构建一个用户友好的…

比例电磁铁控制放大器

GP63系列比例电磁铁应用于电液比例控制系统中&#xff0c;与比例控制放大器配套使用共同控制力士(REXROTH)型十通径螺纹比例阀。在额定行程及额定电流范围内&#xff0c;其输出力与输入电流成比例&#xff0c;通过内置反力弹簧&#xff0c;改变了输出力的特性&#xff0c;使系统…

能源存储蓄电池管理,0基础也能快速上手!

随着能源储存需求的不断增加&#xff0c;蓄电池作为关键的能量储存装置&#xff0c;其稳定性和性能的监测变得尤为重要。 蓄电池监控有助于提高能源系统的可靠性&#xff0c;确保连续供电&#xff0c;同时为维护人员提供及时的故障信息&#xff0c;以便他们能够迅速采取适当的措…

百望云联合华为发布票财税链一体化数智解决方案 赋能企业数字化升级

随着数据跃升为数字经济关键生产要素&#xff0c;数据安全成为整个数字化建设的重中之重。为更好地帮助企业发展&#xff0c;中央及全国和地方政府相继出台了多部与数据相关的政策法规&#xff0c;鼓励各领域服务商提供具有自主创新的软件产品与服务&#xff0c;帮助企业在合规…

【AutoLayout案例03-设置底部按钮之间相同间距 Objective-C语言】

一、好,咱们继续啊 1.咱们继续把autoLayout介绍一下 咱们的自动布局 给大家介绍一下 那么,自动布局呢 继续咱们给大家做的案例 做几个例子 把这几个例子做完以后 我们再给它 我们再给大家说一下,如何通过代码,来实现自动布局 虽然说,通过代码来实现自动布局,并不推荐 但…

AIF360入门教学

1、AIF360简介 AI Fairness 360 工具包(AIF360)是一个开源软件工具包&#xff0c;可以帮助检测和缓解整个AI应用程序生命周期中机器学习模型中的偏见。在整个机器学习的过程中&#xff0c;偏见可能存在于初始训练数据、创建分类器的算法或分类器所做的预测中。AI Fairness 360…

UI自动化测试(下拉框(select类),多窗口,属性,类的方法实战)

一、下拉框&#xff08;select类实现的&#xff09; 在UI的自动化测试实战中&#xff0c;如果遇到下拉框的选择&#xff0c;我们可以使用Select类里面的方法来具体进行定位和解决。下面我们使用HTML的代码来写一个下拉框的页面交互&#xff0c;让大家从直观上知道下拉框的交互…