【C++笔记】内存管理

news2024/10/27 15:26:46

前言

各位读者朋友们大家好,上期我们讲了类和对象下的内容,类和对象整体的内容我们就讲完了,接下来我们开启新的部分内存管理的讲解。

目录

  • 前言
  • 一. C/C++内存分布
  • 二. C语言中内存管理的方式
  • 三. C++内存管理方式
    • 3.1 new/delete操作内置类型
    • 3.2 new和delete操作自定义类型
  • 四. operator new和operator delete函数
    • 4.1 operate new和 operator delete函数
  • 五. new和delete的实现原理
    • 5.1 内置类型
    • 5.2 自定义类型
    • 5.3 使用不匹配
  • 六. 定位new表达式
  • 七. malloc/free和new/delete的区别
  • 结语

一. C/C++内存分布

C/C++的内存分为堆区、栈区、静态区和常量区,我们先来看下面的一段代码和相关问题:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二. C语言中内存管理的方式

malloc/calloc/relloc的区别:

  • malloc是用来在堆区开辟指定字节的函数,返回的是void * 类型的指针。
    在这里插入图片描述
  • calloc函数是用来开辟指定字节空间的函数,并且把开辟的空间的值赋值为0,返回值也是void * 类型的指针。
    在这里插入图片描述
  • realloc函数是用来扩容的函数,第一个形参是要扩容的初始位置的指针,第二个参数是扩容后的空间大小,特别的如果第一个参数传的是空指针,那么realloc函数的功能等同于malloc函数的功能。如果原地扩容成功就返回传过去的指针,如果没有成功就会异地扩容,将原来的数据拷贝到新的位置,再将原位置的空间释放后返回新空间的地址。
    在这里插入图片描述
    在这里插入图片描述
    这里不需要释放p2,因为p3是在p2的基础上扩容的,如果原地扩容成功,p2和p3指向的空间是同一块,所以只需要释放p3即可;如果异地扩容,realloc函数就已经帮我们将p2释放了。

三. C++内存管理方式

C语言的内存管理方式在C++中可以继续使用,但是有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行内存管理。

  • new 运算符用于在堆(heap)上动态分配内存并初始化对象。它返回指向分配的内存块的指针。
  • delete 运算符用于释放先前使用 new 运算符分配的内存。

3.1 new/delete操作内置类型

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],一定要搭配起来使用

3.2 new和delete操作自定义类型

在这里插入图片描述
在这里插入图片描述

这样就很方便了,之前我们写链表要去申请节点,现在我们可以这样写:

struct ListNode
{
	int val;
	ListNode* next;

	ListNode(int x)
		:val(x)
		, next(nullptr)
	{}
};

int main()
{
	ListNode* n1 = new ListNode(1);
	ListNode* n2 = new ListNode(2);
	ListNode* n3 = new ListNode(3);
	ListNode* n4 = new ListNode(4);
	ListNode* n5 = new ListNode(5);
	n1->next = n2;
	n2->next = n3;
	n3->next = n4;
	n4->next = n5;
	return 0;
}

在这里插入图片描述
这样就写好了一个链表。
在这里插入图片描述
在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc和free不会调用。

四. operator new和operator delete函数

4.1 operate new和 operator delete函数

new和delete是用户进行动态内存申请和释放的操作符,operator new和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。在c++中new是operator new 加构造函数,delete是operator delete加析构函数
在这里插入图片描述
在这里插入图片描述
通过上述两个全局函数的实现知道,operator new实际上也是通过malloc来申请空间。如果malloc申请成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该应对措施就继续申请,否则就抛异常。operator delete最终通过free释放空间。

五. new和delete的实现原理

5.1 内置类型

如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:new/delete申请和释放的是单个元素的空间,new[]和delete[]申请和释放的是连续的空间,而且new在申请失败时会抛异常,malloc失败会返回NULL。

5.2 自定义类型

new的原理
在这里插入图片描述
1. 调用operator new函数申请空间
2. 在申请的空间上执行构造函数,完成对对象的构造
delete的原理在这里插入图片描述
1. 在空间上执行析构函数,完成对象中的资源清理工作
2. 调用operator delete函数释放对象的空间
new T[N]的原理
在这里插入图片描述
1. 调用operator new[]函数,在operator new函数完成对N个对象空间的申请
2. 在申请的空间上执行N次构造函数
new T[N]可以理解为执行N次new
delete []的原理
在这里插入图片描述

1. 在释放的对象空间上执行N次析构函数,完成N个对象中的资源清理
2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间
实际上就是执行N次delete

5.3 使用不匹配

  • 内置类型new和free混用
    在这里插入图片描述
    这里不会报错,因为内置类型调用delete时不需要调用析构函数,只调用了_free_dbg也就是free,因此也不会有内存的泄露。但是不建议这样使用。
  • 自定义类型new和delete混用
    在这里插入图片描述
    这里调用free相比调用delete来说少调用了析构函数,如果A的析构函数有对内存的释放就会存在内存泄露的风险。
  • 内置类型new和delete[] 混用
    在这里插入图片描述
    这里不会有内存泄露的风险,因为new 底层调用的malloc,delete底层调用的free。
  • 自定义类型new[]和delete混用
    在这里插入图片描述
    B类中不存在内存的申请和释放,所以不会内存泄漏。
    但是下面这种情况程序会崩:
    在这里插入图片描述
    这是为什么?
class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << "(int a = 0)" << endl;
	}
	A(int a ,int b)
		: _a(a)
		,_b(b)
	{
		cout << "(int a = 0,int b = 0)" << endl;
	}
	~A()
	{
		cout << "~A():" << endl;
	}
private:
	int _a;
	int _b;
};

class B
{
private:
	int _b1 = 520;
	int _b2 = 1314;
};

这里A和B的大小都是8个字节
我们还是从汇编来看:
对于B,编译器给了80个空间
在这里插入图片描述
而同样大小,相同个数的A却开了84字节的空间
在这里插入图片描述
在这里插入图片描述
编译器在给A开空间时多开了4个字节用来存储A的元素个数,而返回的地址却没用从多开的4个字节开始返回,而是往后偏移了4个字节,所以会崩。严格来说两者都应该多开4个字节存元素个数,B没有开是因为编译器优化了,因为编译器看到B没有写析构函数而且没有内存的申请和释放,元素个数是给delete[]用的,当使用delete[]时,指针向前偏移四个字节取到元素个数(释放还是在原位置释放),让编译器知道调几次析构函数。B编译器优化到底,不调用析构函数,所以就不存个数。
如果给B写了析构函数,编译器也会开84个字节的空间:
在这里插入图片描述

六. 定位new表达式

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象
使用格式:
new(place_address)type 或者new(place_address)type(initializer_list)
place_address必须是一个指针,initializer_list是类型的初始化列表
在这里插入图片描述
上图调用operator new只开了空间并没有初始化,
在这里插入图片描述
在这里插入图片描述
使用场景:
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式对其进行显示调用构造函数进行初始化。

七. malloc/free和new/delete的区别

malloc/free和new/delete的共同特点是:都是在堆上申请空间,都需要用户去手动释放。
不同在:

  • 1. malloc和free是函数,new和delete是操作符
  • 2. malloc申请的空间不会初始化,new可以初始化。
  • 3.malloc申请对象时,需要自己计算空间大小并传递,new只需在其后跟上空间类型即可,如果是多个对象,[]中指定个数即可。
  • 4.malloc的返回值是void*,在使用时必须强转,new不需要,因为new后跟的是空间的类型。
  • 5.malloc申请空间失败时,返回的是NULL,所以使用的时候必须判空,new不需要,但是new需要捕获异常。
  • 6.申请自定义类型对象时,malloc/free只会开辟和释放空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理释放.

结语

以上我们就讲完了C++的内存管理,这里还有一些东西没有讲解,需要后续在讲解。感谢大家的阅读,欢迎大家批评指正!

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

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

相关文章

时间序列预测(九)——门控循环单元网络(GRU)

目录 一、GRU结构 二、GRU核心思想 1、更新门&#xff08;Update Gate&#xff09;&#xff1a;决定了当前时刻隐藏状态中旧状态和新候选状态的混合比例。 2、重置门&#xff08;Reset Gate&#xff09;&#xff1a;用于控制前一时刻隐藏状态对当前候选隐藏状态的影响程度。…

idea 无法输入中文 快速解决

idea在某些情况会出现无法输入中文的情况&#xff0c;我们不去深究内部原因&#xff0c;直接上解决方案&#xff1a; 1、点击菜单help->Edit Custom VM Options 2、最后一行&#xff0c;追加&#xff1a; -Drecreate.x11.input.methodtrue 、 3、重启

计算机毕业设计Java连锁超市销售与分析系统 销售数据管理 超市运营分析 数据可视化 (源码+定制+开发)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

10月27日

取P为A 秩1矩阵只有1个特征值为正&#xff0c;其余为1

YOLO11 目标检测 | 自动标注 | 预标注 | 标签格式转换 | 手动校正标签

本文分享使用YOLO11进行目标检测时&#xff0c;实现模型推理预标注、自动标注、标签格式转换、以及使用Labelme手动校正标签等功能。 目录 1、预训练权重 2、生成预标注 3、分析YOLO11的目标检测格式 4、分析Labelme标注工具的格式 5、生成json标注文件 6、手动校正标签 …

#渗透测试#SRC漏洞挖掘# 信息收集-Shodan进阶VNC

免责声明 本教程仅为合法的教学目的而准备&#xff0c;严禁用于任何形式的违法犯罪活动及其他商业行为&#xff0c;在使用本教程前&#xff0c;您应确保该行为符合当地的法律法规&#xff0c;继续阅读即表示您需自行承担所有操作的后果&#xff0c;如有异议&#xff0c;请立即停…

PHPOK 4.8.338 后台任意文件上传漏洞(CVE-2018-12941)复现

PHPOK企业站(简称PHPOK&#xff09;建设系统是一套基于PHP和MySQL构建的高效企业网站建设方案之一&#xff0c;全面针对企业网&#xff08;以展示为中心&#xff09;进行合理的设计规划。 PHPOK是一套开源免费的建站系统&#xff0c;可以在遵守LGPL协议的基础上免费使用。系统具…

trueNas 24.10 docker配置文件daemon.json无法修改(重启被覆盖)解决方案

前言 最近听说truenas的24.10版本开放docker容器解决方案放弃了原来难用的k3s&#xff0c;感觉非常巴适&#xff0c;就研究了一下&#xff0c;首先遇到无法迁移老系统应用问题比较好解决&#xff0c;使用sudo登录ssh临时修改daemon.json重启docker后进行docker start 容器即可…

腾讯云视频文件上传云存储时自动将mp4格式转码成m3u8

针对问题&#xff1a; 弱网环境下或手机网络播放mp4格式视频卡顿。 存储环境&#xff1a;腾讯云对象存储。 处理流程&#xff1a; 1&#xff1a;登录腾讯云控制台&#xff0c;进入对象存储服务&#xff0c;找到对应的存储桶&#xff0c;点击进入。 在任务与工作流选项卡中找…

Linux复习-C++

参考博客&#xff1a; https://blog.csdn.net/qq_45254369/article/details/126023482?ops_request_misc%257B%2522request%255Fid%2522%253A%252277629891-A0F3-4EFC-B1AC-410093596085%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&req…

深入探索:AI模型在各行业的实际应用

深入探索&#xff1a;AI模型在各行业的实际应用 前言一、卷积神经网络&#xff08;CNN&#xff09;图像分类 二、循环神经网络&#xff08;RNN&#xff09;及其变体&#xff08;LSTM、GRU&#xff09;自然语言处理&#xff08;NLP&#xff09; 三、基于Transformer架构的模型&a…

基于树型结构实现顺序结构堆

目录 前言 一、树 1、树的概念与结构 2、树的相关术语 3、二叉树 4、满二叉树 ​ 5、完全二叉树 ​ 6、二叉树的存储 1、顺序结构 2、链式结构 二、堆 1、堆的结构 2、堆的初始化 3、入堆&#xff08;大根堆&#xff09; 4、出堆&#xff08;大根堆&#xf…

C++网络编程之C/S模型

C网络编程之C/S模型 引言 在网络编程中&#xff0c;C/S&#xff08;Client/Server&#xff0c;客户端/服务器&#xff09;模型是一种最基本且广泛应用的架构模式。这种模型将应用程序分为两个部分&#xff1a;服务器&#xff08;Server&#xff09;和客户端&#xff08;Clien…

Java审计对比工具JaVers使用

最近有个需求&#xff0c;需要将页面的内容生成excel或者word文档&#xff0c;而且每次的修改都需要生成新的版本&#xff0c;同时需要记录每次修改变化的内容。我们会把每次的修改的内容提交赋值给一个java对象&#xff0c;同时存储到数据库一条新数据&#xff0c;对应数据表一…

uniapp圆形波浪进度效果

uniapp圆形波浪进度效果 背景实现思路代码实现尾巴 背景 最近项目中有些统计的地方需要用到圆形的波浪进度效果&#xff0c;要求是根据百分比值然后在一个圆形内动态的展示一个波浪形的进度&#xff0c;看参考一下效果。 实现思路 这个效果看着挺复杂的&#xff0c;那么我们…

android——渐变色

1、xml的方式实现渐变色 效果图&#xff1a; xml的代码&#xff1a; <?xml version"1.0" encoding"utf-8"?> <shape xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools…

索引的使用和优化

索引就是一种快速查询和检索数据的数据结构&#xff0c;mysql中的索引结构有&#xff1a;B树和Hash。 索引的作用就相当于目录的作用&#xff0c;我么只需先去目录里面查找字的位置&#xff0c;然后回家诶翻到那一页就行了&#xff0c;这样查找非常快&#xff0c; 创建一个表结…

【数据结构】宜宾大学-计院-实验五

实验五 栈和队列&#xff08;队列的基本操作&#xff09; 实验目的&#xff1a;链表结点结构&#xff1a;实验结果&#xff1a;运行截图&#xff1a;代码实现&#xff1a; 实验目的&#xff1a; 1&#xff0e;掌握队列的顺序存储结构和链式存储结构 2&#xff0e;实现队列的基…

(北京政务服务满意度公司)满意度调查助力服务质量提升

在当今社会&#xff0c;&#xff08;政务服务满意度公司&#xff09;政务窗口服务的质量直接关系到市民的日常生活和城市的健康发展。为了解市民对政务窗口服务的满意度&#xff0c;提升服务质量&#xff0c;某市委托民安智库专业市场调查公司开展了政务窗口服务满意度调查&…

若依框架部署到服务器刷新或者是退出登录出现404

登出错误404 改成/登出的时候重定向到根路径&#xff0c;让nginx匹配去找dist目录下的index.html文件 或者是直接改为/index.html&#xff0c;少一步可能会快一点&#xff1f; 不过会变得很丑,算了还是根目录吧 原版是index&#xff0c;那玩意是 针对路由的&#xff0c;而打包…