C/C++内存管理

目录

前言

1、C/C++内存划分

2、C语言中的动态内存管理方式

3、C++内存管理方式

 3.1操作内置类型

3.2操作自定义类型

3.3为什么对应的new和delete必须搭配使用(了解)

4、operator new与operator delete函数

5、new和delete的实现原理

5.1内置类型

5.2自定义类型

6、 malloc/free和new/delete的区别


前言

  在上一篇文章中我们讲完了类和对象的基本内容,而大家也知道,C++是一个注重底层逻辑的语言,所以我们这一篇文章讲一讲C语言和C++中的内存管理,让大家对底层内存的划分和内存管理的方式(也就是如何开辟空间与销毁空间有一个较为浅显的认知)

1、C/C++内存划分

  C/C++在内存划分上是一致的,都是按照下图的样式进行划分的。

【说明】

1. 栈又叫堆栈--非静态局部变量/函数参数/返回值等等,栈是向下增长的。

2. 内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口 创建共享共享内存,做进程间通信。

3. 堆用于程序运行时动态内存分配,堆是可以上增长的。

4. 数据段--存储全局数据和静态数据。

5. 代码段--可执行的代码/只读常量。

  栈区的空间较小,通常只有几个MB,但是堆区空间相对较大,有几个GB,所以不用怕申请空间时不够用,还有一点就是字符串数组放在栈区,而字符串是常量,放在代码段。

2、C语言中的动态内存管理方式

  C语言中是通过malloc/calloc/realloc/free这几个函数进行动态内存管理的,相信这些内容大家在C语言中已经学过了这几个函数,就简单描述一下区别:

1、malloc直接开辟空间,不对空间进行初始化

2、calloc在开辟空间的同时,还会把空间里的内容初始化为0

3、realloc不能直接开辟空间,它是用于对malloc和calloc开辟的内存进行扩充。

3、C++内存管理方式

 3.1操作内置类型

  大家都知道C++是对C语言的改进与优化,而C语言中动态开辟方式较为繁琐,还需要进行强制类型转换等,所以就有了new和delete两个操作符

void Test()
{// 动态申请一个int类型的空间int* ptr4 = new int;// 动态申请一个int类型的空间并初始化为10int* ptr5 = new int(10);// 动态申请10个int类型的空间int* ptr6 = new int[3];delete ptr4;delete ptr5;delete[] ptr6;
}

 但是大家需要注意的是申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用 new[]和delete[],两者不能混合使用。

  

3.2操作自定义类型

  new/delete和malloc/free对于内置类型上的作用基本没有区别,但是在自定义类型中会有区别,申请的是自定义类型空间时,new同时会调用构造函数,delete会调用析构函数,而malloc和free不会

class A
{
public:A(int a = 0): _a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}
private:int _a;
};
int main()
{// new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间//还会调用构造函数和析构函数A* p1 = (A*)malloc(sizeof(A));A* p2 = new A(1);free(p1);delete p2;// 内置类型是几乎是一样的int* p3 = (int*)malloc(sizeof(int)); // Cint* p4 = new int;free(p3);delete p4;A* p5 = (A*)malloc(sizeof(A) * 10);A* p6 = new A[10];free(p5);delete[] p6;return 0;
}

之前一直说 new 类型【】,delete【】和 new 类型,delete必须搭配使用,为什么呢,我们来简要讲解一下,下面内容大家了解即可,不必深究。

3.3为什么对应的new和delete必须搭配使用(了解)

  当然,如果大家搭配使用,会发现有的时候编译器并不会报错,甚至有时候报错了,再重新运行一次又没错误了。我们以下述例子为例,讲解一下:

  当你以开辟了一个内置类型数组空间时,用如下方式:

int main()
{int* ptr = new int[10];delete ptr;return 0;
}

你虽然混合使用了new 类型【】和delete,但是编译器并没有报错,但是当你换为自定义类型后就有可能会报错,那么什么情况下会报错呢,就是你显式写了析构函数,那么为什么会报错呢,我们来讲解一下:

int main()
{A* ptr = new A[10];delete ptr;return 0;
}

当你上述代码正确使用,即使用delete【10】 ptr;时你转到汇编语言你会发现(这里我们假设申请的空间ptr为80个字节),我们真实申请出的空间并不是80个字节,而是84个字节,为什么会多申请4个字节呢,其实这个这多申请的四个字节是用来存放具体开辟了几个A类型对象大小的空间,就比如说以上例子,存储的就是10,真实开辟的空间大致如下:

 此时因为你用的是delete【】,所以编译器会自动向前移动四个字节,把开辟出的84个字节全部清理掉,但是如果你用的delete,还显式写出了析构函数,那么就会报错,因为你是从开辟的空间的中间开始析构的,这是不被允许的,如果你没有显式写出析构函数,编译器会认为你没有开辟空间,自然也就不会开辟那四个字节的空间,所以你析构的位置就是正确的。

 多余开辟的四个字节的空间其实是为了告诉delete,我们到底开辟了几个自定义类型大小的空间,但是如果是内置类型,就不会开辟这一个整形的空间,因为编译器自己底层会处理,至于如何处理,不必深究。

 讲到这里,如果大家能看懂,应该就知道为什么不能混用了吧。那我们接着来将后续内容吧!!!

4、operator new与operator delete函数

  new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过 operator delete全局函数来释放空间。

  那大家可能不理解为什么已经有了malloc和free,还要搞出new和delete呢,其实C++是一个比较喜欢将异常抛出的语言,而不是像malloc一样开辟空间失败会返回NULL,但是其实new的底层时operator new,而operator new的底层是malloc。

  operator new和operator delete并不是运算符重载,他们就是两个函数。

  operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间 失败,尝试执行空间不足应对措施,如果用户设置了应对措施,则继续申请,否则抛异常,程序终止。

  当抛出异常,我们就可以使用try{} catch(){}对异常进行捕获,这个后面会学,了解一下即可。

  operator delete: 该函数最终是通过free来释放空间的。

  通过上述内容我们可以知道,operator new 实际也是通过malloc来申请空间,如果 malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。

5、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[]中实际调用operator new函数完成N个对象空间的申请

2. 在申请的空间上执行N次构造函数

⚪delete[]的原理

1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理

2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间

 最后,我们来说一下malloc/free和new/delete的区别。

6、 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在释放空间前会调用析构函数完成空间中资源的清理释放

到这里,内存管理我们大致就讲完了,有写的不好的地方希望大家斧正,感谢大家。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微软开源GraphRAG的使用教程-使用自定义数据测试GraphRAG

微软在今年4月份的时候提出了GraphRAG的概念&#xff0c;然后在上周开源了GraphRAG,Github链接见https://github.com/microsoft/graphrag,截止当前&#xff0c;已有6900Star。 安装教程 官方推荐使用Python3.10-3.12版本&#xff0c;我使用Python3.10版本安装时&#xff0c;在…

RK3568平台开发系列讲解(调试篇)网卡队列均衡负载

🚀返回专栏总目录 文章目录 一、RPS 的介绍1. RPS 的工作原理2. RPS 配置3. 启用和调优 RPS4. RPS 优势二、下行测试iperf测试沉淀、分享、成长,让自己和他人都能有所收获!😄 RPS(Receive Packet Steering) 是一种用于提高网络接收性能的技术,通常用于多核处理器系统中…

RagFlow + Docker Desktop + Ollama + DeepSeek-R1本地部署自己的本地AI大模型工具

前期准备 首先&#xff0c;我们需要下载 Ollama 以及配置相关环境。 Ollama 的 GitHub仓库 &#xff08;https://github.com/ollama/ollama&#xff09;中提供了详细的说明&#xff0c;简单总结如下: Step1&#xff1a;下载 Ollama 下载&#xff08;https://ollama.com/dow…

变分边界详解

起因 当时看VAE论文时有这么一段&#xff0c;但是看完直接一头雾水&#xff0c;这都那跟哪&#xff0c;第一个公式咋做的变换就变出那么一堆。网上搜了很多博客都语焉不详&#xff0c;只好自己来写一篇&#xff0c;希望能解答后来人的疑惑。 公式1 参考文章&#xff1a;证据…

云消息队列 ApsaraMQ Serverless 演进:高弹性低成本、更稳定更安全、智能化免运维

如今&#xff0c;消息队列已成为分布式架构中不可或缺的关键服务&#xff0c;为电商、物联网、游戏和教育等行业&#xff0c;提供了异步解耦、集成、高性能和高可靠的核心价值。 过去一年&#xff0c;我们发布了云消息队列 ApsaraMQ 全系列产品 Serverless 化&#xff0c;面向…

【蓝桥杯嵌入式】8_IIC通信-eeprom读写

全部代码网盘自取 链接&#xff1a;https://pan.baidu.com/s/1PX2NCQxnADxYBQx5CsOgPA?pwd3ii2 提取码&#xff1a;3ii2 1、电路图 这个电路允许通过I2C总线与EEPROM(M24C02-WMN6TP)和数字电位器(MCP4017T-104ELT)进行通信。EEPROM用于存储数据&#xff0c;而数字电位器可以用…

DeepSeek处理自有业务的案例:让AI给你写一份小众编辑器(EverEdit)的语法着色文件

1 DeepSeek处理自有业务的案例&#xff1a;让AI给你写一份小众编辑器(EverEdit)的语法着色文件 1.1 背景 AI能力再强&#xff0c;如果不能在企业的自有业务上产生助益&#xff0c;那基本也是一无是处。将企业的自有业务上传到线上训练&#xff0c;那是脑子进水的做法&#xff…

Java常用设计模式面试题总结(内容详细,简单易懂)

设计模式的分类 创建型模式&#xff1a;通过隐藏对象创建的细节&#xff0c;避免直接使用 new 关键字实例化对象&#xff0c;从而使程序在判断和创建对象时更具灵活性。常见的模式包括&#xff1a; 工厂模式抽象工厂模式单例模式建造者模式原型模式 结构型模式&#xff1a;通…

使用HX搭建UNI-APP云开发项目(适合新手小白与想学云开发的宝子)

什么是uni-app云开发 uni-app云开发是uni-app提供的一套后端服务,它可以帮助开发者快速搭建起一个完整的后端服务,包括数据库、云函数、存储等。开发者只需要关注前端页面的开发,后端服务由uni-app云开发提供。 uni-app云开发的优势: 快速搭建后端服务:uni-app云开发提供了…

零基础学CocosCreator·第九季-网络游戏同步策略与ESC架构

课程里的版本好像是1.9&#xff0c;目前使用版本为3.8.3 开始~ 目录 状态同步帧同步帧同步客户端帧同步服务端ECS框架概念ECS的解释ECS的特点EntityComponentSystemWorld ECS实现逻辑帧&渲染帧 ECS框架使用帧同步&ECS 状态同步 一般游戏的同步策略有两种&#xff1a;…

最新版Edge浏览器集成ActiveX控件之金山WpsDocFrame控件

背景 WpsDocFrame控件‌是由金山公司开发的ActiveX控件&#xff0c;主要用于OA系统中&#xff0c;支持在浏览器中嵌入WPS文档的查看和编辑功能。 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品&#xff0c;致力于将浏览器插件重新应用到所有…

Win10系统IP地址修改_出现了一个意外的情况不能完成所有你在设置中所要求的更改---Windows工作笔记001

今天在修改win10系统中的ip地址的时候报错了 来看看如何解决吧,挺简单,简单记录一下 这个时候就需要使用cmd命令来修改 一定要使用,管理员权限,运行cmd才可以 然后首先: 输入 netsh 然后输入 ip 然后输入: set address "以太网" 172.19.126.199 255.255.255.0…

算法 ST表

目录 前言 一&#xff0c;暴力法 二&#xff0c;打表法 三&#xff0c;ST表 四&#xff0c;ST表的代码实现 总结 前言 ST表的主要作用是在一个区间里面寻找最大值&#xff0c;具有快速查找的功能&#xff0c;此表有些难&#xff0c;读者可以借助我的文章和网上的课程结…

node.js+兰空图床实现随机图

之前博客一直用的公共的随机图API&#xff0c;虽然图片的质量都挺不错的&#xff0c;但是稳定性都比较一般&#xff0c;遂打算使用之前部署的兰空图床&#xff0c;自己弄一个随机图 本文章服务器操作基于雨云——新一代云服务提供商的云服务器进行操作&#xff0c;有兴趣的话可…

CNN|ResNet-50

导入数据 import matplotlib.pyplot as plt # 支持中文 plt.rcParams[font.sans-serif] [SimHei] # 用来正常显示中文标签 plt.rcParams[axes.unicode_minus] False # 用来正常显示负号import os,PIL,pathlib import numpy as npfrom tensorflow import keras from tensor…

基于微型5G网关的石化厂区巡检机器人应用

石化工业属于高风险产业&#xff0c;由于涉及易燃易爆、有毒有害工业原料&#xff0c;为了保障企业的安全生产与持续运营&#xff0c;因此相比其它行业需要进行更高频次、更全面细致的安全巡检和监测。由于传统的人工巡检监测存在诸多不便&#xff0c;例如工作强度大、现场环境…

Docker+Jenkins自动化部署SpringBoot项目【详解git,jdk,maven,ssh配置等各种配置,附有示例+代码】

文章目录 DockerJenkins部署SpringBoot项目一.准备工作1.1安装jdk111.2安装Maven 二.Docker安装Jenkins2.1安装Docker2.2 安装Jenkins2.3进入jenkins 三.Jenkins设置3.1安装jenkins插件3.2全局工具配置全局配置jdk全局配置maven全局配置git 3.3 系统配置安装 Publish Over SSH …

知识图谱数据库 Neo4j in Docker笔记

下载 docker pull neo4j:community官方说明 https://neo4j.com/docs/operations-manual/2025.01/docker/introduction/ 启动 docker run \--restart always \--publish7474:7474 --publish7687:7687 \--env NEO4J_AUTHneo4j/your_password \--volumeD:\files\knowledgegrap…

前缀和算法篇:解决子数组累加和问题

1.前缀和原理 那么在介绍前缀和的原理之前&#xff0c;那么我们先来说下前缀和最基本的一个应用场景&#xff0c;那么就是如我们标题所说的子数组累加和问题&#xff0c;那么假设我们现在有一个区间为[L,R]的数组&#xff0c;那么我们要求的其中子数组比如[L,i]或者[i,m] (L&l…

Notepad++ 中删除所有以 “pdf“ 结尾的行

Notepad 中删除所有以 “pdf” 结尾的行 操作步骤 1.打开文件&#xff1a; 在 Notepad 中打开你需要处理的文本文件。 2.打开查找和替换对话框&#xff1a; 按快捷键 Ctrl F&#xff0c;打开“查找和替换”对话框。 3.启用正则表达式模式&#xff1a; 在对话框的底部&#xf…