“智能指针:C++中优雅的内存管理解决方案“

news2024/11/23 18:33:18

在这里插入图片描述

前言

欢迎来到💖小K💖的💞C++专栏💞,内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,这是C和C++程序员的噩梦之一。本节将为大家带来解决办法—>智能指针

在这里插入图片描述

文章目录

      • 前言
      • 1、简介
      • 2、为什么要使用智能指针
      • 3、unique_ptr
      • 4、shared_ptr
      • 5、weak_ptr

1、简介

✨智能指针是一个模板类,封装了裸指针,可以对指针进行安全的操作。

  • 使用RAII特点,将对象生命周期使用栈来管理
  • 智能指针区分了所有权,因此使用责任更为清晰
  • 智能指针大量使用操作符重载和函数内联特点,调用成本和裸指针无差别

2、为什么要使用智能指针

✨一句话:智能指针就是帮我们C++程序员管理动态分配的内存的,它会帮助我们自动释放new出来的内存,从而避免内存泄漏!

✨内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,这是C和C++程序员的噩梦之一。

3、unique_ptr

✨unique_ptr是一种定义在中的智能指针(smart pointer)。它持有对对象的独有权——两个unique_ptr不能指向一个对象,不能进行复制操作只能进行移动操作。

unique_ptr对象是管理的对象的唯一拥有者:因为当unique_ptr对象释放时会删除它们的托管对象,而不考虑其他指针是否仍然指向相同的对象,从而使指向那里的其他指针指向无效的位置。

unique_ptr对象复制了有限的指针功能,通过操作符*和->(用于单个对象)或操作符[](用于数组对象)提供对其托管对象的访问。出于安全考虑,它们不支持指针算术运算,只支持移动赋值(禁用复制赋值)。

✨下面是基本的使用方法

void testOne() 
{
	unique_ptr<int> p(new int(1234));
	cout << *p << endl;
	unique_ptr<int> p1;
	//p1 = p;                     错误,不能赋值和拷贝
	//unique_ptr<int> p2(p);
	p1 = move(p);           //转交所有权
	cout << *p1 << endl;
	//cout << *p << endl;   //错误,p已经失去了管理对象

	unique_ptr<int> p3(new int(897));
	p3.reset(p1.release());
	cout << *p3 << endl;
}

✨需要手动写删除器的情况,一般是操作自定义类型(且注意unique_ptr的删除器写法的,需要手动写入删除器类型)

class MM {
public:
	~MM() {
		cout << "调用析构函数成功" << endl;
	}
};
void testTwo() 
{
	//unique_ptr删除器写法,需要手动写入删除器类型
	unique_ptr<MM,void(*)(MM*&)> Pmm(new MM[4], [](MM*& pmm) {delete[] pmm; });
}

注意当函数参数为unique_ptr类型时,需要使用引用,因为此类型是独享型,禁止拷贝

void print(unique_ptr<int>& p) 
{
	cout << *p << endl;
}

4、shared_ptr

✨unique_ptr是一个独享指针,同一时刻只能有一个unique_ptr指向一个对象,而shared_ptr是一个共享指针,同一时刻可以有多个shared_ptr指向同一对象,但会记录有多少个shared_ptr共同指向一个对象。这便是所谓的引用计数(reference counting)。

✨ 一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。这在非环形数据结构中防止资源泄露很有帮助。

基本用法

void testOne() 
{
	shared_ptr<int> p1; //无参构造
	if (!p1) 
	{
		cout << "空的智能指针对象" << endl;
	}
	shared_ptr<int> p2(new int(1234));
	//shared_ptr<int> p2 = new int(1234); 错误

	shared_ptr<int> p3 = make_shared<int>(1234);  //使用make_shared不支持创建数组
	//怎么访问数据,直接把智能指针对象当做指针来用
	cout << *p3 << endl;
	//cout << p3[0] << endl; 错误,没有下标的使用方式

	//获取管理对象原生指针
	int* k = p3.get();
	cout << *k << endl;
	cout << k[0] << endl;
	//注意:千万不要手动释放原生指针,否则会中断(释放两次)
	//delete k;

	cout << "管理对象数:" << p3.use_count() << endl;
	shared_ptr<int> p4(p3);
	cout << "管理对象数:" << p3.use_count() << endl;

}

vector管理普通指针的弊端

class MM 
{
public:
	MM(string name="",int age=0):name(name),age(age){}
	void print() 
	{
		cout << name << "\t" << age << endl;
	}
	~MM() 
	{
		cout << "调用析构函数" << endl;
	}
protected:
	string name;
	int age;
};
void testTwo() 
{
	cout <<"-----------------------------------" << endl;
	shared_ptr<MM> p(new MM("name1", 19));
	p->print();

	/*****************vector弊端*****************/
	vector<MM*> p1;
	p1.push_back(new MM("name", 20));
	//p1.pop_back();
	p1.clear();
	//可以看到pop和clear函数都不会自动调用析构函数---->当vector操作自定义类型指针的时候
	/*******************************************/

	//比较常用的用法--->工作中
	vector<shared_ptr<MM>> arr;
	shared_ptr<MM> p2(new MM("name"));
	p2->print();
	arr.push_back(p2);
}

上面代码中,当vector管理MM*类型的时候,并不会自动调用析构函数,这时候我们只需要让vector管理shared_ptr就好了

需要手动写删除器的情况,和unique_ptr一样

void testThree() 
{
	cout << "-----------------------------------" << endl;
	shared_ptr<int> king(new int[4] {1, 2, 3, 4});
	int* pNum = king.get();
	for (int i = 0; i < 4; i++)
	{
		cout << pNum[i] << " ";
	}
	cout << endl;

	//当操作特殊类型(自定义类型,c语言文件的打开)的时候,需要手动写删除器
	shared_ptr<MM> p1(new MM[4], [](MM*& pmm) {delete[]pmm; });
	shared_ptr<FILE> pfile(fopen("1.txt", "w+"), [](FILE*& file) {free(file); });
}

✨当shared_ptr当函数参数和返回值的时候,正常写就ok

void pprint(shared_ptr<MM>& mm) {
	mm->print();
}
shared_ptr<int> returnpoint(int num) {
	return shared_ptr<int>(new int(num));
}

5、weak_ptr

shared_ptr可以用来避免内存泄漏,可以自动释放内存。但是在使用中可能存在循环引用,使引用计数失效,从而导致内存泄漏的情况。如下代码所示:

class B;
class A {
public:
	~A() {
		cout << "A" << endl;
	}
	shared_ptr<B> a;
};
class B {
public:
	~B() {
		cout << "B" << endl;
	}
	shared_ptr<A> b;
};
void testOne() 
{
	shared_ptr<A> ao(new A);
	shared_ptr<B> bo(new B);
	ao->a = bo;
	bo->b = ao;
}

我们发现上面的一段代码中,ao中的指针管理bo,bo中的指针管理ao,形成了循环管理,这时候就不会自动释放。这时候我们只需要把shared_ptr改为weak_ptr就ok了

基本处理

weak_ptr只能从shared_ptr或者已有的weak_ptr去构造,不能直接管理对象
不能直接访问管理的对象,访问数据要通过lock()函数去访问shared_ptr,然后再去访问数据

void testTwo() 
{
	shared_ptr<int> p(new int(1234));
	cout << "count:" << p.use_count() << endl;
	weak_ptr<int> w(p);
	cout << "count:" << w.use_count() << endl;
	weak_ptr<int> w2(w);
	cout << "count:" << w2.use_count() << endl;
	cout << *w.lock() << endl;
	shared_ptr<int> k = w2.lock();
	cout << *k << endl;
}

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

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

相关文章

【移动端网页布局】flex 弹性布局 ⑤ ( 设置侧轴单行子元素排列方式 | align-items 样式说明 | 代码示例 )

文章目录 一、设置子元素是否换行 : align-items 样式说明1、 align-items 样式引入2、 align-items 样式属性值 二、代码示例1、 代码示例 - 默认样式2、 代码示例 - 设置主轴水平居中3、 代码示例 - 设置侧轴垂直居中4、 代码示例 - 设置侧轴从下到上排列5、 代码示例 - 设置…

C++之类和对象(二)

目录 前言 类的6个默认成员函数 1.构造函数 1.1 概念 1.2 特性 2. 析构函数 2.1 概念 2.2 特性 3. 拷贝构造函数 3.1 概念 3.2 特征 4.赋值运算符重载 4.1 运算符重载 4.2.赋值运算符重载 4.3 前置和后置重载 5. .const成员 6.取地址及const取地址操作符重载 前…

【二叉搜索树】

1 二叉搜索树概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树 &#xff0c;或者是具有以下性质的二叉树 : 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值 若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值 它的左…

Android“真正的”模块化

作者&#xff1a;bytebeats 模块化背后的原则概述 “如果说SOLID原则告诉我们如何将砖块排列成墙和房间, 那么组件原则则告诉我们如何将房间排列成建筑.” ~ Robert C. Martin, Clean Architecture 你应该分层打包还是分特性打包?还有其他方法吗? 如何提高项目的编译时间? 你…

将Python环境迁移到另一台设备上

本方法可以将一台电脑上的python环境迁移到另一台电脑上&#xff0c;可以省去一个一个包pip的麻烦。本文以pytorch的迁移为例。 一、从源环境备份安装包 在原来的电脑的Conda控制台中使用语句 pip freeze > c:\myrequirement.txt 后面跟的参数是文件的路径和文件名&#x…

Spring MVC自定义拦截器--Spring MVC异常处理

目录 自定义拦截器 什么是拦截器 ● 说明 自定义拦截器执行流程分析图 ● 自定义拦截器执行流程说明 自定义拦截器应用实例 ● 应用实例需求 创建MyInterceptor01 创建FurnHandler类 在 springDispatcherServlet-servlet.xml 配置拦截器 第一种配置方式 第二种配置方…

linux 互斥量pthread_mutex

专栏内容&#xff1a;linux下并发编程个人主页&#xff1a;我的主页座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物&#xff0e; 目录 前言 概述 原理 初始化 进程和线程使用的不同点 死锁 接口 基本API 属性设置 …

探索机器翻译:从统计机器翻译到神经机器翻译

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

Osek网络管理及ETAS实现

OSEK/VDX&#xff08;Offene Systeme und deren Schnittstellen fr die Elektronik in Kraftfahrzeugen / Vehicle Distributed eXecutive&#xff09;是一种用于嵌入式系统&#xff08;尤其是汽车电子控制单元&#xff09;的开放标准。它旨在提供一种统一、可互操作的软件架构…

关于 《python 从入门到实践》的 matplotlib 随机漫步小项目

使用 python 生成随机漫步数据&#xff0c;再使用 matplotlib 将数据呈现。 所谓随机漫步&#xff1a; 每次行走的路径都是完全随机的&#xff0c;就像蚂蚁在晕头转向的情况下&#xff0c;每次都沿随机方向前行路径。 在自然界&#xff0c;物理学&#xff0c;生物学&#xff0…

【Linux】Job for network.service failed(网卡启动报错)

上图是Linux网卡启动报错的情况 这是由于cat/etc/sysconfig/network-scripts/ifcfg-xxx 中HWADDR的MAC地址和ifconfig中的MAC地址不一样&#xff0c;或者缺少cat/etc/sysconfig/network-scripts/ifcfg-xxx 中HWADDR的MAC地址 1.查看ifconfig中的MAC地址 图中00&#xff1a;0c…

【新星计划-2023】IP地址是什么?IP地址的主要功能是什么?

IP地址在生活中是很常见的&#xff0c;我们所使用的手机、电脑等等&#xff0c;都有一个IP地址&#xff0c;那么IP地址是什么&#xff1f;通过IP地址又能干什么&#xff1f;下文就来给大家详细的讲解一下。 一、什么是IP地址 通常我们说的IP地址多数是指互联网中联网的IP地址…

Java 基础进阶篇(十一)—— Arrays 与 Collections 工具类

文章目录 一、Arrays工具类1.1 Arrays 类常用方法1.2 对于 Comparator 比较器的支持1.3 Arrays 的综合应用1.3.1 应用一&#xff1a;数组的降序排序1.3.2 应用二&#xff1a;根据学生年龄进行排序 二、Collections工具类2.1 Collections 类常用方法2.2 Collections 排序相关 AP…

神经网络实验---梯度下降法

本次实验主要目的是掌握梯度下降法的基本原理&#xff0c;能够使用梯度下降法求解一元和多元线性回归问题。 文章目录 目录 文章目录 1. 实验目的 2. 实验内容 3. 实验过程 题目一&#xff1a; 题目二&#xff1a; 题目三&#xff1a; 实验小结&讨论题 1. 实验目的 ① 掌握…

〖Python网络爬虫实战㉓〗- Ajax数据爬取之什么是Ajax

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;目前专栏免费订阅&#xff0c;在转为付费专栏前订阅本专栏的&#xff0c;可以免费订阅付…

23.5.7总结(学习通项目思路)

项目思路&#xff1a; 注册&#xff1a;输入邮箱&#xff08;判重&#xff09;&#xff0c;两次输入密码&#xff0c;获得的正确的验证码&#xff0c;获得不重复的用户名。 登录&#xff1a;输入用户名和密码登录。 忘记密码&#xff1a;输入邮箱&#xff08;和用户名&#…

RK3588平台开发系列讲解(进程篇)可执行文件内部结构

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、 ELF 文件的两大组成部分二、文件头三、程序头和节区头四、ELF 文件的细节结构沉淀、分享、成长,让自己和他人都能有所收获!😄 📢在 Linux 中,二进制可执行文件的标准格式叫做 ELF(Executable and Linkabl…

ARP协议结构

文章目录 概念ARP协议格式ARP协议的作用ARP协议的工作流程 首先提出一个问题&#xff0c;来理解ARP解决什么问题 已知报文在数据链路层传输的过程中&#xff08;假设是主机A到主机B&#xff09;&#xff0c;是通过路由器之间的跳转&#xff0c;根据路由表&#xff0c;结合目的…

【论文】SimCLS:一个简单的框架 摘要总结的对比学习(1)

SimCLS:摘要总结的对比学习(1&#xff09; 写在最前面模型框架 摘要1 简介 写在最前面 SimCLS: A Simple Framework for Contrastive Learning of Abstractive Summarization&#xff08;2021ACL会议&#xff09; https://arxiv.org/abs/2106.01890 论文&#xff1a;https://…

【c语言小demo】登录demo | 账号密码验证功能

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ …