C++进阶--智能指针

news2024/12/25 12:50:48

智能指针的概念

智能指针是C++中的一个重要概念,用于管理动态分配的对象内存它是一个类模板,通过封装原始指针,并在对象生命周期结束时自动释放内存,从而避免了内存泄漏和资源管理的繁琐工作

C++标准库提供了多种常见的智能指针,目前常用的有:unique_ptr , shared_ptr , weak_ptr。(头文件: < memory >

为什么需要智能指针?

看一个例子:

int div()
{
	int a, b;
	cin >> a >> b;
	if (b == 0)
		throw invalid_argument("除0错误");
	return a / b;
}
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;
}
int main()
{
	try
	{
		Func();
	}
	catch (exception& e)
	{
		cout << e.what() << endl;
	}
	return 0;
}

在这里插入图片描述

RAll

RAII(Resource Acquisition Is Initialization)的核心思想是资源的获取和释放应该与对象的生命周期绑定在一起。当一个对象被创建时,它应该获取所需要的资源;当对象被销毁时,它应该释放已经获取的资源。这样可以确保资源在不再需要时被正确释放,从而避免资源泄漏。

利用RAll原理做出智能指针

代码:

template<class T>
class SmartPtr
{
public:
	//RALL
	SmartPtr(T* ptr)
		:_ptr(ptr)
	{}

	~SmartPtr()
	{
		cout << "delete: " << _ptr<< endl;
		delete _ptr;
	}

	//解引用
	T& operator*()
	{
		return *_ptr;
	}
	//指针形式
	T* operator->()
	{
		return _ptr;
	}
private:
	T* _ptr;
};

利用RAll原理制作智能指针:
在这里插入图片描述
在这里插入图片描述

测试:在这里插入图片描述
在这里插入图片描述

auto_ptr

在这里插入图片描述

简单使用

在这里插入图片描述
在这里插入图片描述
由于这种智能指针不能对实际应用起到作用,所以现在大多数程序员都没有用到它。

要模拟实现一个auto_ptr时,只需要在上面代码的赋值拷贝中加上:
在这里插入图片描述

unique_ptr

unique_ptr与常规指针的一个主要区别就是:它拥有对指向对象的独占拥有权。这意味着同一时间只能有一个unique_ptr指向某个对象,不能进行复制操作,只能进行移动操作。当unique_ptr被销毁或重置时,他所指向的对象也会自动删除。

模拟实现

template<class T>
	class unique_ptr
	{
	public:
		unique_ptr(T* ptr)
			:_ptr(ptr)
		{}

		unique_ptr(unique_ptr<T>& p)= delete;
		unique_ptr operator=(const unique_ptr<T>& p) = delete;

		~unique_ptr()
		{
			cout << "delete:" << _ptr << endl;

			delete _ptr;
		}

		// 像指针一样
		T& operator*()
		{
			return *_ptr;
		}

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

实现时只需要对默认拷贝构造和默认赋值构造给它删除了,那么就实现了不能对它进行复制了。

测试:
在这里插入图片描述

shared_ptr

在这里插入图片描述

为什么不能用static成员来进行计数?

在这里插入图片描述

模拟实现

template<class T>
	class shared_ptr
	{
	public:
		//常规使用的构造函数
		shared_ptr(T* ptr = nullptr)
			: _ptr(ptr),
			_count(new int(1))
		{}

		//sp2(sp1)
		shared_ptr(const shared_ptr<T>& sp)
		{
			_ptr = sp._ptr;
			_count = sp._count;

			//拷贝后将count+1
			++(*_count);
		}

		//sp3=sp1
		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			if (_ptr != sp._ptr)
			{
				//使用赋值时,要考虑之前的智能指针指向的空间
				release();
				_ptr = sp._ptr;
				_count = sp._count;
				//拷贝后将count+1
				++(*_count);
			}

			return *this;
		}
		//释放资源
		void release()
		{
			if (--(*_count) == 0)
			{
				cout << "delete:" << _ptr << endl;
				delete _ptr;
				delete _count;
			}
		}
		~shared_ptr()
		{
			//当count为0时触发
			release();
		}

		int use_count()
		{
			return *_count;
		}

		// 像指针一样
		T& operator*()
		{
			return *_ptr;
		}

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

		T* get() const
		{
			return _ptr;
		}
	private:
		T* _ptr;
		int* _count;
	};

解释:
在这里插入图片描述

测试:
在这里插入图片描述

赋值时必须要对之前智能指针指向的空间进行检查:
在这里插入图片描述

验证解引用:
在这里插入图片描述

定制删除器

在这里插入图片描述
在类中添加一个成员:
在这里插入图片描述
在这里插入图片描述
添加一个构造函数的重载:
在这里插入图片描述
在这里插入图片描述
释放时的修改:
在这里插入图片描述

template <class T>
struct ArrayDelete
{
	void operator()(T* ptr)
	{
		delete[] ptr;
	}
};
//定制删除器
int main()
{
	fnc::shared_ptr<ListNode> n(new ListNode(10));
 	fnc::shared_ptr<ListNode> n1(new ListNode[10],ArrayDelete<ListNode>());
	fnc::shared_ptr<FILE> n2(fopen("FileName.cpp", "r"), [](FILE* file) {fclose(file); });
}

在这里插入图片描述

智能指针的缺陷

struct ListNode
{
	int _val;

	fnc::shared_ptr<ListNode> _next;
	fnc::shared_ptr<ListNode> _prev;
	
	ListNode(int val=0)
		:_val(val)
	{}
};

int main()
{
	fnc::shared_ptr<ListNode> n1(new ListNode(10));
	fnc::shared_ptr<ListNode> n2(new ListNode(20));

	cout << n1.use_count() << endl;
	cout << n2.use_count() << endl;

	n1->_next = n2;
	n2->_prev = n1;

	cout << n1.use_count() << endl;
	cout << n2.use_count() << endl;

	//delete n1;
	//delete n2;

	return 0;
}

结果:
在这里插入图片描述
在这里插入图片描述

weak_ptr

weak_ptr就是用于解决循环引用的问题。它与shared_ptr配合使用,可以指向一个由shared_ptr管理的对象,但不会增加该对象的引用计数。

weak_ptr不拥有所指对象的拥有权,当指向对象被释放时,weak_ptr会自动失效,不再指向有效的对象

	template<class T>
	class weak_ptr
	{
	public:
		// RAll
		weak_ptr()
			:_ptr(nullptr)
		{}

		weak_ptr(const shared_ptr<T>& sp)
		{
			_ptr = sp.get();
		}

		weak_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			_ptr = sp.get();
			return *this;
		}

		// 像指针一样
		T& operator*()
		{
			return *_ptr;
		}

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

	private:
		T* _ptr;
	};

将LIstNode的next指针和prev指针类型改为weak_ptr的:
在这里插入图片描述
结果:
在这里插入图片描述

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

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

相关文章

MySQL常见问题与解决方案详述

MySQL&#xff1a;常见问题与解决方案详述 作为一款广泛使用的开源关系型数据库管理系统&#xff0c;MySQL对于初学者来说既充满吸引力又充满挑战。本文将列举初学者在使用MySQL过程中可能遇到的一些典型问题&#xff0c;并提供详细的解决方案&#xff0c;配以图片辅助说明&am…

Visual Studio 对 C++ 头文件和模块的支持

在 C 编程领域&#xff0c;头文件和模块的管理有时候确实比较令人头疼。但是&#xff0c;有许多工具和功能可以简化此过程&#xff0c;提高效率并减少出错的可能性。下面是我们为 C 头文件和模块提供的几种工具的介绍。 构建明细 通过菜单栏 Build > Run Build Insights&a…

Eudic欧路词典for Mac:专业英语学习工具

Eudic欧路词典for Mac&#xff0c;作为专为Mac用户设计的英语学习工具&#xff0c;凭借其简捷高效的特点&#xff0c;成为众多英语学习者不可或缺的助手。 Eudic欧路词典for Mac v4.6.4激活版下载 这款词典整合了多个权威词典资源&#xff0c;如牛津、柯林斯、朗文等&#xff0…

低代码技术的全面应用:加速创新、降低成本

引言 在当今数字化转型的时代&#xff0c;企业和组织面临着不断增长的应用程序需求&#xff0c;以支持其业务运营和创新。然而&#xff0c;传统的软件开发方法通常需要大量的时间、资源和专业技能&#xff0c;限制了企业快速响应市场变化和业务需求的能力。在这样的背景下&…

杰发科技AC7840——CAN通信简介(7)_波形分析

参考&#xff1a; CAN总线协议_stm32_mustfeng-GitCode 开源社区 0. 简介 隐形和显性波形 整帧数据表示 1. 字节描述 CAN数据帧标准格式域段域段名位宽&#xff1a;bit描述帧起始SOF(Start Of Frame)1数据帧起始标志&#xff0c;固定为1bit显性(b0)仲裁段dentify(ID)11本数…

HarmonyOS开发案例:【 自定义弹窗】

介绍 基于ArkTS的声明式开发范式实现了三种不同的弹窗&#xff0c;第一种直接使用公共组件&#xff0c;后两种使用CustomDialogController实现自定义弹窗&#xff0c;效果如图所示&#xff1a; 相关概念 [AlertDialog]&#xff1a;警告弹窗&#xff0c;可设置文本内容和响应回…

视频输入c++ 调用 libtorch推理

1、支持GPU情况 libtorch 支持GPU情况比较奇怪&#xff0c;目前2.3 版本需要在链接器里面加上以下命令&#xff0c;否则不会支持gpu -INCLUDE:?ignore_this_library_placeholderYAHXZ 2 探测是否支持 加一个函数看你是否支持torch&#xff0c;不然不清楚&#xff0c;看到…

数据库和表创建练习

一丶要求 1.创建一个数据库db_classes 2 创建一行表db_hero 3. 将四大名著中的常见人物插入这个英雄表 二丶创建db_classes一个数据库, 使用数据库默认的字符集 create database db_classes; 三丶创建一行表db_hero 1.先切换到我们创建的db_classes;数据库中 use db_class…

HTTP的MIME 类型(2024-04-27)

1、简介 MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的标准&#xff0c;用来表示文档、文件或字节流的性质和格式。 MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据。 浏览器通常使用 MIME 类型&#xff08;而不是文件扩展名&…

打包的意义 作用等前端概念集合 webpack基础配置等

基础网页是什么&#xff1f; 在学校最基础的三剑客 原生JS CSS H5就可以开发静态网页了 对于浏览器而言也能识别这些基础的文件和语法&#xff0c;真正的所见即所得&#xff0c;非常直接。 为什么要使用框架库&#xff1f; 对于常用的前端框架而言&#xff0c;无论是Vue Rea…

【面试经典 150 | 回溯】组合

文章目录 写在前面Tag题目来源解题思路方法一&#xff1a;回溯 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等内容进行回顾…

企业微信开发

侧边栏开发 企业内应用 创建应用 录入必要信息 配置 网页授权及JS-SDK 需要按照提示&#xff0c;把认证的txt暴露出来&#xff0c;能够访问即可。 下图为认证成功的截图 配置侧边栏工具栏 录入页面名称&#xff08;tab页展示名&#xff09;、页面URL 配置授权可信ip 用于…

boa交叉编译(移植到arm)

参考&#xff1a;CentOS7 boa服务器的搭建和配置-CSDN博客 以下操作在宿主机/编译平台操作&#xff1a; 1. 先执行[参考]1到3、 4.2、4.3、4.4、4.5 2. 修改MakeFile # 由以下&#xff1a; CC gcc CPP gcc -E # 改为&#xff1a; CC arm-linux-gnueabihf-gcc CPP arm-l…

019基于JavaWeb的在线音乐系统(含论文)

019基于JavaWeb的在线音乐系统&#xff08;含论文&#xff09; 开发环境&#xff1a; Jdk7(8)Tomcat7(8)MysqlIntelliJ IDEA(Eclipse) 数据库&#xff1a; MySQL 技术&#xff1a; JavaServletJqueryJavaScriptAjaxJSPBootstrap 适用于&#xff1a; 课程设计&#xff0c;毕…

Prometheus数据模型与查询语言:构建高效监控系统的关键

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Prometheus&#xff1a;监控的神》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Prometheus诞生史 二、Prometheus的数据模型与查询语…

零基础HTML教程(31)--HTML5多媒体

文章目录 1. 背景2. audio音频3. video视频4. audio与video常用属性5. 小结 1. 背景 在H5之前&#xff0c;我们要在网页上播放音频、视频&#xff0c;需要借助第三方插件。 这些插件里面最火的就是Flash了&#xff0c;使用它有几个问题&#xff1a; 首先要单独安装Flash&…

物资管理的挑战与机遇:利用技术提升效率与可持续性

引言 物资管理在企业运营中扮演着至关重要的角色。有效的物资管理不仅能够确保企业正常生产和运营所需的物资供应&#xff0c;还能够最大程度地优化资源利用、降低成本、提高效率&#xff0c;从而增强企业的竞争力和可持续发展能力。然而&#xff0c;在当今复杂的全球供应链环境…

WebSocket的原理、作用、API、常见注解和生命周期的简单介绍,附带SpringBoot示例

文章目录 原理作用客户端 API服务端 API生命周期常见注解SpringBoot示例 WebSocket是一种 通信协议 &#xff0c;它在 客户端和服务器之间建立了一个双向通信的网络连接 。WebSocket是一种基于TCP连接上进行 全双工通信 的 协议 。 WebSocket允许客户端和服务器在 单个TCP连接上…

逆数对(树状数组的方法)

本题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 题目&#xff1a; 样例&#xff1a; 输入 5 4 5 1 3 2 输出 7 思路&#xff1a; 根据题意&#xff0c;求逆序对总数。 逆序对含义&#xff1a;如果数组中的两个不同位置&#xff0c;前面的数字比后面的数字严格大&…

websocket爬虫

人群看板需求分析 先找到策略中心具体的数据。对应数据库中的数据 看看接口是否需要被逆向 点开消费者细分&#xff0c;可以找到人群包&#xff08;人群名称&#xff09; 点击查看透视 label字段分类: 在这里插入图片描述 预测年龄&#xff1a;tagTitle 苹果id&#x…