C++ | 动态内存管理 new、delete (用法、底层)详解
目录
简单回顾C语言动态内存管理
new、delete的用法
内置类型
new
delete
自定义类型
new、delete底层讲解(重要)
operator new 与 operator delete
定位 new
结语
简单回顾C语言动态内存管理
在C语言的学习阶段
我们接触到了三个能在堆上开辟空间的函数——malloc、calloc、realloc
其中,malloc是开辟空间但是不初始化,calloc是开辟空间并且会将空间内容都初始化为0,而realloc则主要用于扩容,如果传入的指针为空,则效果和malloc一致
realloc又分为原地扩容和异地扩容
原地扩容就是扩容后的空间直接在原空间上往后延申,但有一个前提,就是在后扩展这段空间里面不能存在数据阻挡,否则就会变成异地扩
异地扩容就是原空间后面有被使用的空间,导致无法直接原地扩容,就需要另外开辟一块完整空间,最后再将数据拷贝到新空间,原空间销毁
但是在C++就不一样了,C++中的new会更为简洁,各位看官且往下看
new、delete的用法
内置类型
new
我们在C++如果要使用C语言中的malloc、calloc、realloc也是可以的,因为C++兼容C语言
但是日常没有人会这么用,因为有更好的选择——new
我们在C++中如果想要动态开辟一个空间,可以选择直接new,如下:
int main()
{//动态开辟一块空间int* ptr = new int;return 0;
}
如果我们要连续开辟一段空间呢?比如开辟10个,如下:
int main()
{//动态开辟一块空间int* ptr1 = new int;//动态开辟一段空间int* ptr2 = new int[10];return 0;
}
那如果我想要开辟了空间之后进行初始化呢?也是可以的,我们先来看单单开辟了一个空间的情况:
int main()
{//动态开辟一块空间并初始化int* ptr1 = new int(5);return 0;
}
接着我们再来看一看一段空间的情况:
int main()
{//动态开辟一段空间并初始化int* ptr2 = new int[10] {1, 2, 3, 4, 5, 6};return 0;
}
如上,我们会看到我们开辟了一段空间,如果要初始化的话,后面就需要跟上花括号{},而如上代码我们只输入了6个数字,这也就代表着我们对应的初始化了前六个,而后面剩下的四个则会默认初始化为0
delete
同样的,C语言中清除空间有free,在C++中对应有delete,如下展示几个例子:
int main()
{//动态开辟一块空间int* ptr1 = new int;delete ptr1;//动态开辟一块空间并初始化int* ptr2 = new int(5);delete ptr2;//动态开辟一段空间int* ptr3 = new int[10];delete[] ptr3;//动态开辟一段空间并初始化int* ptr4 = new int[10] {1, 2, 3, 4, 5, 6};delete[] ptr4;return 0;
}
如上我们可以看到,C++中的delete一共有俩种用法——delete、delete[]
当只有单独一个空间的时候,就使用delete
当有一段空间的时候,就使用delete[]
当然这也比较好记,因为这也和new一一对应
如上都是针对内置类型的情况,但其实祖师爷搞出这块儿主要针对的是自定义类型
自定义类型
我们先来写一个类,在该类的构造函数和析构函数里面分别打印一些内容方便我们检查结果
struct A
{A(){cout << "A()" << " ";}~A(){cout << "~A()" << " " ;}
};
然后我们再使用我们的new:
int main()
{A* a1 = new A;delete a1;cout << endl << endl;A* a2 = new A[10];cout << endl;delete[] a2;return 0;
}
我们可以看到,当我们使用了new来开辟一块A类型的空间的时候,他会在开辟空间的同时,还会调用对应的构造函数
如果是开辟了一段空间比如10个的话,就会连续调用10次构造函数并开辟对应大小的空间
而我们的delete就相反,他会调用对应的析构,如果是连续的就连续调用多次析构并销毁相应空间
new、delete底层讲解(重要)
operator new 与 operator delete
operator new 和 operator delete对标的是malloc和free
也就是说,这个就是开辟空间的,如果我们去看源码的话,我们会发现,operator new 其实就是对malloc的一个封装,operator new 的底层就是malloc,operator delete同理
但是好好的为什么要对 malloc 封装呢?直接用 malloc 不好吗?
各位回想一下,我们每次在使用完malloc之后,都需要检查一下空间有没有开辟成功,如果没有开辟成功,我们还需要进行返回,而且每写一个就需要检查一下,写10个malloc就需要对应写10个检查,这样子写得确实有点恼火
而在C语言种检查错误用的是错误码,是errno
但是C++使用了一种给更好的方法——异常(这个知识太超纲了,后面会重点学,这里知道即可)
所以本质上,operator new 就是对 malloc 和异常进行了一个封装,这也就使得C++中的new变得异常简洁,因为我们不需要检查,直接使用new即可,new里面有operator new,operator new 有malloc 和异常,所以我们不需要检查
但是我们上面又看到,开辟一个自定义类型的时候,还会调用其构造函数
综上,我们可以 得出一个结果:
new = operator new + 构造函数
operator new = malloc + 异常(错误检查)
相对的,delete也是大差不差,但是operator delete可没有异常,祖师爷在这块设计成这样单纯是为了对称,所以:
delete = operator delete+ 析构函数
operator delete = free
同理,再来看看 new[],其本质就是多次调用operator new和构造,仅此而已,delete[] 同理
也就是在内部会多开四个字节用来记录连续开了几块空间,再根据这四个字节里面的内容,来决定到底要调用几次构造,几次析构,简图如以下(假设连续开辟10个空间):
定位 new
一般情况下,我们会使用new,而new会自动调用构造函数
但是我们会遇到一个情况,这个情况出现在内存池中:我们如果频繁地申请空间,会使效率变低,所以就有了内存池,要申请先申请一大块空间,需要申请就到内存池中申请,内存池空间不够了再到堆里面去
但是,我们如果要在内存池中申请空间的话,就不能使用new,因为new默认会调用堆上面的空间,所以我们只能使用operator new,但是我们这时候需要在类外面调用构造,可是析构能在类外面显式调用,但是构造不行,所以就有了定位new的产生
定位new的语法有点子奇怪:
new (place_address) type或者new (place_address) type(initializer-list)
举个例子:
A* ptr = (A*)operator new(sizeof(A));
new(ptr)A(10); //定位newptr->~A();
operator delete(ptr);
如上这是只申请一块空间的情况,但如果是operator new[]的话,就应该写一个for循环,循环的次数就是需要调用构造函数的次数
A* ptr = (A*)operator new(sizeof(A) * 10);
for(int i = 0; i < 10; i++)new(ptr+i)A(5); //定位newfor(int i = 0; i < 10; i++)(ptr+i)->~A();
operator delete[](ptr);
结语
这篇博客详细讲解了C++中的动态内存管理,如果觉得对你有帮助的话,希望可以多多支持!!❀
相关文章:

C++ | 动态内存管理 new、delete (用法、底层)详解
目录 简单回顾C语言动态内存管理 new、delete的用法 内置类型 new delete 自定义类型 new、delete底层讲解(重要) operator new 与 operator delete 定位 new 结语 简单回顾C语言动态内存管理 在C语言的学习阶段 我们接触到了三个能在堆上开辟…...

【C语言】结构体内存布局解析——字节对齐
🦄个人主页:小米里的大麦-CSDN博客 🎏所属专栏:https://blog.csdn.net/huangcancan666/category_12718530.html 🎁代码托管:黄灿灿 (huang-cancan-xbc) - Gitee.com ⚙️操作环境:Visual Studio 2022 目录 一、引言 二、什么是字节对齐&…...
模型表达方式
目录 一、模型表达概述 二、模型精确表达 2.1 几何表示 (Geometrical Representation) 三、模型非精确表达 3.1 网格表示 (Mesh Representation) 3.2 体素表示 (Voxel Representation) 一、模型表达概述 模型的表达方式多种多样,选择适合的表达方式取决于具体应用场景和…...

校园课程助手【4】-使用Elasticsearch实现课程检索
本节将介绍本项目的查询模块,使用Elasticsearch又不是查询接口,具体流程如图所示(如果不了解Elasticsearch可以使用sql语句进行查询): 这里是两种方法的异同点: Mysql:擅长事务类型操作&#…...
经典运维面试题
1、Linux常见的日志文件都有哪些,各自的用途?日志轮询配置文件在哪里?欢迎界面配置文件在哪里? /var/log/messages #内核及公共消息日志/var/log/cron #计划任务日志/var/log/dmesg #系统引导日志/var/log/malilog #邮件系…...

别再盲目推广了!Xinstall助你开启App线下推广新篇章
在这个数字化飞速发展的时代,App已经成为我们生活中不可或缺的一部分。然而,App市场的竞争也日益激烈,如何让你的App在众多竞争者中脱颖而出,成为每个推广者必须面对的问题。今天,就让我们一起探讨一下App线下推广的痛…...

大厂linux面试题攻略五之数据库管理
一、数据库管理-MySQL语句 0.MySQL基本语句: 1.SQL语句-增 创建xxx用户: mysql>create user xxx % indentified by 123456; xxx表示用户名 %b表示该用户用来连接数据库的方式(远程或本地连接) indentified by 123456设置密码…...
【pytorch】模型集成
在集成学习中,我们会训练多个模型(通常称为「弱学习器」)解决相同的问题,并将它们结合起来以获得更好的结果。最重要的假设是:当弱模型被正确组合时,我们可以得到更精确和/或更鲁棒的模型。 常用的模型集成…...

初识集合和数据结构
目录 初识集合框架数据结构基本概念和术语数据数据元素数据项数据对象前四者的关系数据结构逻辑结构和物理结构逻辑结构物理结构 算法算法设计要求 初识集合框架 Java的集合框架也可被称为容器,是定义在Java.util包下的一些接口和实现类。其就是将多个元素存储到一…...

cocos creator 3.x中动态加载 resources 文件夹下的图片时提示找不到
文件目录如下 类型为spriteFrame 代码案例 图片设置为 sprite-frame、texture 或其他图片类型后,将会在 资源管理器 中生成一个对应类型的资源。但如果直接加载 equipments/testea,得到的类型将会是 ImageAsset,必须指定路径到具体的子资源…...
第九十八周周报
学习时间: 2024.7.27-204.8.3 学习产出: 这周主要在按照审稿人的意见修改论文,由于有个模型保存的文件找不到了,所以重新训练花了点时间,目前已经把修改后的论文和cover letter发给杨老师了。...
程序员找工作之数据结构面试题总结分析
文章目录 1. 数据结构的基本概念与分类2. 数据结构的存储与表示3. 数据元素的存储与关系4. 存储结构的选择与考量5. 特定数据结构的定义与特性6. 数据结构操作与应用7. 数组与存储8. 特定数据结构的存储与访问 程序员在找工作面试中,数据结构方面可能会被问到的问题…...
设置provider解决maven找不到JUnit 5测试样例
问题描述 尝试复现一个用大模型生成测试样例的工作,但使用maven生成的JUnit 5测试样例死活不执行。又不想用命令行运行,因此进行排查 基本知识 <dependencies> junit-jupiter-api JUnit 5写代码时调用的库 junit-jupyter-engine 运行JUnit 5测…...

php反序列化靶机serial实战
扫描ip,找到靶机ip后进入 他说这是cookie的测试网页,我们抓个包,得到cookie值 base64解码 扫描一下靶机ip的目录 发现http://192.168.88.153/backup/,访问 下载一下发现是他的网页源码 通过代码审计,发现 通过代码审计得知&…...

类型推断技术及仓颉语言实践
史磊 仓颉语言类型推断技术专家 一、一种看待类型系统的方式 一门编程语言一定得包含类型系统吗? 这个问题今天看来可能显而易见,一个程序没有类型的话还能算是个完整、正确的程序吗?但是其实关于类型系统的作用,一直是存在两种…...

职场生存秘籍:16条黄金法则
作者简介:一名计算机萌新、前来进行学习VUE,让我们一起进步吧。 座右铭:低头赶路,敬事如仪 个人主页:我叫于豆豆吖的主页 写在前面 在这个瞬息万变的时代,职场不仅是实现个人价值与梦想的舞台,更是一…...

Flask 介绍
Flask 介绍 为什么要学 Flask框架对比设计哲学功能特点适用场景学习曲线总结 Flask 的特点Flask 常用扩展包Flask 的基本组件Flask 的应用场景官方文档官方文档链接文档内容概述学习建议 Flask 是一个使用 Python 编写的轻量级 Web 应用框架。它旨在让 Web 开发变得快速、简单且…...

JAVA基础知识点3 (String 和 StringBuffer 以及 StringBuilder 的特点以及区别)
1,String 和 StringBuffer 以及 StringBuilder 的特点 (1)String的特点:String是final修饰的字符序列是不可改变的, 是字符串常量,一旦初始化就不可以被更改,因此是线程安全的 因为是常量每次对其操作都会…...

2024年8月AI内容生成技术的现状与未来:从文生文到跨模态交互的全景分析
2024年8月AI内容生成技术的现状与未来:从文生文到跨模态交互的全景分析 大家好,我是猫头虎!🚀 随着AI在内容生成领域的爆发式发展,从2022年末开始,AI生成技术已经走过了文生文(AIGC)…...

File 34
package File;import java.awt.*; import java.io.File;public class file1 {public static void main(String[] args) {//创建FILE对象,指代某个具体的文件//路径分隔符File f1new File("C:/Users/SUI/Desktop/kaishi/nih.txt");// File f1new File(&quo…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...

算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...

【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...

Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...