【C++】C++的内存管理

目录

 

内存分布

动态内存管理

C语言的动态内存管理

C++的动态内存管理

对内置类型操作

对自定义类型操作

new[]和delete[]

开空间的细节

探讨匹配问题

定位new表达式


 

内存分布

栈:存放非静态局部变量,函数参数,返回值等。栈是向下增长的。

堆:用于动态内存分配,堆是向上增长的。

数据段:存放全局数据,静态数据。

代码段:可执行代码,只读常量

内存映射段:是高效的I/O映射方式,用于装载一个共享的动态内存库。用户可以使用系统接口创建共享内存,做进程间通信
示意图
db9b1641210f47ea8cc52a5e8351d06e.png
下面代码中的变量都在哪里呢
int a = 0;
static int b = 0;void Teat()
{int c = 0;static int d = 0;int num[10] = { 0 };char char2[] = "abcd";const char* pc = "abcd"; int* ptr = (int*)malloc(sizeof(int) * 4);free(ptr);
}

解析

9f4be9feeb5c4f5d9bd1f1deddd279be.png


动态内存管理

C语言的动态内存管理

void * malloc(size_t size) 
在堆上开辟空间
开辟失败返回NULL
返回值要检查是否为空
接受返回值需要强转
void * calloc(size_t num, size_t size)
再堆上开辟num个size大小的空间,并把该空间初始化为0
开辟失败返回NULL
返回值要检查是否为空
接受返回值需要强转
void * realloc(void* ptr, size_t size) // (动态内存空间, 新空间的大小)
调整原有空间
调整失败返回NULL
不会初始化空间
用新的指针接收

C++的动态内存管理

C++兼容C语言,C语言的动态内存管理方式依然在C++中能用。但在C++的大部分场景中,C语言的动态内存管理方式并不适用。

C++引入了两个关键字

new:在堆上开辟空间

delete:释放new开辟的空间

对内置类型操作

对于内置类型而言,new和delete与C语言的动态内存管理基本一致

开辟一个int类型的空间

int* ptr = new int;

开辟一个int类型的空间,并初始化为0

int* ptr = new int(0);

释放空间

delete ptr;

开辟10个int类型的空间,并初始化

int* ptr = new int[10]{1, 2, 3, 4, 5, 6};

后面会自动补0

c3547abe170a4288b12bd01b40d03d0b.png

释放该空间

delete[] ptr;

注意:new和delete匹配,new[]和delete[]匹配。如果不匹配会怎么样,对内置类型来说最多是警告。1dc5f1c396b247048e971a4ca081c41f.png

对自定义类型操作

引入new和delete就是为了应对自定义类型

new在堆上开辟空间时,还会调用构造函数

delete释放堆上的空间时,还会调用析构函数

详解构造函数:http://t.csdnimg.cn/TZLEB

小编会用下述代码带大家感受一下这两点

class Date //日期类
{
public:Date() //构造函数:_a(new int[7]{0}) //为_a开空间   初始化列表,_year(2024),_month(4),_day (24){cout << "构造函数" << endl;}~Date() //析构函数{delete[] _a;  //释放_a的空间cout << "析构函数" << endl;}private:int _year;  //年int _month; //月int _day;  //日int* _a;  //指针};
Date* ptr = new Date;           delete ptr;  

new示意图6d2bdc83b25e4aa896641579bc0a9be3.png

delete示意图

3885b790077e4fab9b55e58831116e5f.png

而C语言的malloc()不能调用构造free()不能调用析构。所以C语言的动态内存管理对自定义类型并不适用。

注意:对自定义类型来说,new和delete要匹配,new[]和delete[]要匹配,为什么要匹配小编后面会细讲

operator newoperator delete函数

operator newoperator delete 是系统的全局函数。

new操作符底层调用的是operator new ,delete操作符底层调用的是operator delete。

速览定义

3fb8eed3549c4b779808179484c0f817.png83a0cdf692fd4a098f7f9819de2163d0.pngoperator new 的底层实际上还是由malloc开的空间,可以说operator new是malloc的封装。

operator delete 的底层调用的是free,operator delete 是 free的封装。

直接让new操作符调用malloc不好吗,为什么要把malloc封一层 operator new呢?

如果malloc开辟空间失败,会返回NULL。我们会手动检查接收的指针是否为空,并给自己提示错误码。而operator new 开辟空间失败会抛异常。

抛异常提示的信息会比错误码丰富,当程序运行到异常的地方时,程序会跳转到相应异常的地方处理代码。(这里只是简单的提一下抛异常的好处,让大家理解为什么要对malloc进行封装)

下面是operator new的一部分源码

void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{
// report no memory
// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}

下面是 operator delete 的部分源码

void operator delete(void *pUserData)
{
_CrtMemBlockHeader * pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK); /* block other threads */
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg( pUserData, pHead->nBlockUse );
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
}

new[]和delete[]

new[]底层会调用operator new[],operator new[]底层会调用N次operator new 来为N个对象在堆上开辟空间。然后在申请的空间上调用N次构造函数。

示意图

28836757d0804e3aaac48356ec2768ec.png

delete[]会先调用N次析构对要释放空间进行数据和资源的清理,然后会调用operator delete[] ,operator delete[]会再调用operator delete释放该空间

示意图

818b74f041d44a9f8673fa98dd1dc426.png

开空间的细节

new[]在开空间时会多开4个字节或8个字节多开的空间用于储存new[]开空间的个数

小编用如下代码调试,带大家感受一下

class TestClass //测试类
{
public:TestClass(int a = 0)  //构造函数: _a(a){cout << "TestClass():" << this << endl; //打印对象的地址}~TestClass() //析构函数{cout << "~TestClass():" << this << endl; }
private:int _a; //私有数据
};void Test() //测试函数
{TestClass* ptr = new TestClass[5]; //在堆上实例化5个对象delete[] ptr; //释放空间}int main()
{Test();  
}

new5个对象

f0a519d9205542fab91196906abb7c19.png释放空间

07c2c5aff81148fea1b65847899b475f.png

小编解释一下具体的过程

首先new[]会先为5个对象开辟空间,并额外开4字节或8字节的空间来记录对象的个数。然后调用5次构造函数为空间中的数据初始化。

delete[]会先调用5次析构清理空间的数据,delete[]最底层的free会在额外空间的地址往后释放空间。

开额外空间记录对象的个数是为了让编译器直到要调用几次析构函数,因为我们并不会给delete[]传对象的个数

至此,我们再来探讨一下delete和new与delete[]和new[]的匹配问题

探讨匹配问题

内置类型:在堆上开空间时不涉及调用构造函数和析构函数,也不涉及复杂的内存分配。如果不匹配,出问题的几率不大(小编不鼓励大家这么写代码)。

自定义类型:一定要匹配!!!我们把两种不匹配的情况都分析一下

new和delete[]

TestClass* ptr = new TestClass; //在堆上实例化5个对象  delete[] ptr; //释放空间

如果new和delete[]匹配会发生很有意思的情况

为什么会一直调用析构函数呢?因为new不会额外开空间,而delete[]会把对象的前4个或8个字节存的值当作析构函数调用的次数,但这个值是个随机值。

这是一个很严重的问题,一直被调用的析构函数不是只作用于一块空间,对象后面的空间都会被析构函数无差别的攻击。

这就像一个有着高机动性并且可以随意篡改内存的野指针。

这样写编译器不会强制报错,大家一定要注意

new[]和delete

Date* ptr = new Date[5];
delete ptr;  

首先,编译器会给出警告

49b71aa87df44150a0d3415e22fc3a03.png

代码也跑不动

75ecaf4987c4417ca451a18d2835a026.png

这里就会发生很明显的内存泄露。deleete[]额外开的空间不会被释放。因为delete只会调用一次析构,对象空间的数据和资源不会清理干净。new[]和delete匹配会强制报错。


定位new表达式

了解即可

作用:为了能显示的调用对象的构造函数

写法

new(指向对象的指针)构造函数名

new(ptr)TestClass;  

new(指向对象的指针)构造函数名type(初始化列表)

new(ptr)TestClass[1, 2, 3, 4, 5];

上述代码用到了隐式类型转换,可以参考一下小编的这篇文章http://t.csdnimg.cn/5yM0z


本篇的内容到此结束啦

 

 

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

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

相关文章

Vim学习笔记01~04

第01章&#xff1a; 遁入空门&#xff0c;模式当道 1.什么是vim Vim是一个高效的文本编辑工具&#xff0c;并且可以在编程开发过程中发挥越来越重要的作用。 事实上&#xff0c;有不少编程高手使用他们来进行代码的开发&#xff0c;并且对此赞不绝口。 2.本系列目的 但是让…

微信小程序按钮点击时的样式hover-class=“hover“

小程序的button组件很好用&#xff0c;按钮点击的时候会显示点击状态&#xff0c;默认的就是颜色加深 但是我们改变了button的背景色之后&#xff0c;就看不出点击效果了&#xff0c;解决起来也很简单 关键代码就是小程序的 hover-class 属性&#xff0c;需要注意的是&#xff…

代码随想录算法训练营Day8 | ● 344.反转字符串● 541. 反转字符串II● 54.替换数字● 151.翻转字符串里的单词● 55.右旋转字符串

&#xff08;记得重学&#xff09; ● 344.反转字符串 题目&#xff1a;编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间&#xff0c;你必须原地修改输入数组、使用 O(1) 的额外空间解决这一…

Qt [获取Dump] 使用WindowsAPI实现生成MiniDump文件

说明 客户现场的软件偶发崩溃是程序开发者&#xff0c;比较头疼的事情。如何更快速的定位到问题点和解决掉&#xff0c;是开发应该具备的基本能力。 Windows提供了一系列的API&#xff0c;可以记录软件崩溃前的堆栈信息。下面就实现一个生成Dump文件的程序实例。 主要代码 回…

计算机系列之输入输出、中断、总线、可靠性、操作系统、进程管理、同步互斥

9、输入输出-中断-总线-可靠性 1、输入输出技术、中断 1、内存与接口地址的编址方法&#xff08;了解概念即可&#xff09; 计算机系统中存在多种内存与接口地址的编址方法&#xff0c;常见的是下面两种&#xff1a;&#xff08;了解概念即可&#xff09; 1&#xff09;内存…

ai大模型应用开发

随着人工智能技术的飞速发展&#xff0c;AI大模型应用开发已成为一个日益重要的领域。本文将从专业角度深入探讨AI大模型的应用开发&#xff0c;并思考其未来的深度影响和逻辑性。 编辑搜图 请点击输入图片描述&#xff08;最多18字&#xff09; ​【一、AI大模型的定义与特点…

ASP.NET Core 3 高级编程(第8版) 学习笔记 03

本篇介绍原书的第 18 章&#xff0c;为 19 章 Restful Service 编写基础代码。本章实现了如下内容&#xff1a; 1&#xff09;使用 Entity Framework Core 操作 Sql Server 数据库 2&#xff09;Entity Framework Core 数据库迁移和使用种子数据的方法 3&#xff09;使用中间件…

Babylon.js 读取GLB模型元数据

如果你熟悉将 3D 资源导出到游戏引擎的过程&#xff0c;那么无疑也会熟悉 3D 资源的 PBR 和 GLB 导出过程。 这是我们之前概述的内容&#xff0c;也是我们交互式工作的所有资产准备的基石。 然而&#xff0c;从传统的管道意义上来说&#xff0c;能够用元数据标记网格有很多逻辑…

通配符HTTPS安全证书

众多类型的SSL证书&#xff0c;要说适用或者说省钱肯定是通配符了&#xff0c;因为谁都想一本SSL证书包括了整条域名&#xff0c;而且也不用一条一条单独管理。 通配符HTTPS安全证书&#xff0c;其实就是通配符SSL证书&#xff0c;SSL证书主流CA的参数都一样&#xff0c;通配符…

武汉星起航:亚马逊助力中国卖家扬帆出海,迎来跨境电商新机遇

2015年&#xff0c;亚马逊全球开店业务正式踏入中国这片充满活力和潜力的市场&#xff0c;此举不仅为中国卖家提供了前所未有的跨境电商新机遇&#xff0c;更为其发展出口业务、拓展全球市场、打造国际品牌铺设了一条坚实的道路。亚马逊作为国际版的电商购物平台&#xff0c;其…

Hadoop-Hive-Spark-离线环境搭建

一、版本描述 apache-hive-2.3.9-bin.tar.gz hadoop-2.7.0.tar.gz spark-2.4.0-bin-hadoop2.7.tgz 下载链接&#xff1a; https://archive.apache.org/dist/spark/spark-2.4.0/spark-2.4.0-bin-hadoop2.7.tgz https://archive.apache.org/dist/hadoop/common/hadoop-2.7.…

vscode 创建代码模版

在vscode中快捷创建代码模版 1.在VSCode中&#xff0c;按下Ctrl Shift P&#xff08;Windows/Linux&#xff09;或Cmd Shift P&#xff08;Mac&#xff09;打开命令面板。 2.然后输入"Preferences: Configure User Snippets"并选择该选项。打开一个json文件用户…

IDEA中配置使用maven和配置maven的中央仓库

1 以汉化后的IDEA为例配置maven 打开idea选择文件 选择 设置 点击>构建.执行.部署 点击>构建工具 点击>Maven 其中Maven主路径 就是我们maven下载解压后的路径 可以通过边上的三个点选择你解压后的绝对路径&#xff0c;也可以直接把解压后的绝对路劲复制过来 以下…

回归预测 | Matlab实现SSA-ESN基于麻雀搜索算法优化回声状态网络的多输入单输出回归预测

回归预测 | Matlab实现SSA-ESN基于麻雀搜索算法优化回声状态网络的多输入单输出回归预测 目录 回归预测 | Matlab实现SSA-ESN基于麻雀搜索算法优化回声状态网络的多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现SSA-ESN基于麻雀搜索算法…

物联网:从电信物联开发平台AIoT获取物联设备上报数据示例

设备接入到电信AIoT物联平台后&#xff0c;可以在平台上查询到设备上报的数据。 下面就以接入的NBIOT物联远传水表为例。 在产品中选择指定设备&#xff0c;在数据查看中可以看到此设备上报的数据。 示例中这组数据是base64位加密的&#xff0c;获取后还需要转换解密。 而我…

2024 IDM最新破解版及软件介绍

*IDM&#xff1a;信息时代的高效管理工具** 在快节奏的现代社会中&#xff0c;随着信息的爆炸式增长&#xff0c;如何高效、有序地管理信息成为每个人都需要面对的挑战。IDM&#xff0c;作为一种信息管理工具&#xff0c;正在逐渐受到人们的青睐。 IDM&#xff0c;全称Inform…

Linux--进程控制(1)

文章衔接&#xff1a; Linux--环境变量-CSDN博客 Linux--地址空间-CSDN博客 目录 1.进程创建 2.进程的终止 2.1想明白&#xff1a;终止是在做什么&#xff1f; 2.2进程终止的三种情况 2.3 进程如何终止 3.进程等待 &#xff08;wait/waitpid&#xff09; 1.进程创建 在li…

C++内存分布 new和delete介绍

目录 C/C内存分布 栈区 堆区 静态区 常量区 C new和delete 分配空间形式对比 new delete与malloc free的区别 可不可以串着使用new和free呢 C/C内存分布 C的内存分布&#xff0c;大体上分为栈区 堆区 静态区 常量区 栈区 栈区是用于存储函数调用时的局部变量 函…

MySQL——运维

日志 错误日志 错误日志是 MySQL 中最重要的日志之一&#xff0c;它记录了当 mysqld 启动和停止时&#xff0c;以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时&#xff0c;建议首先查看此日志。 查看日志位置&#xff1a; sho…

Eigen::svd和 np.linalg.svd的不同之处

目录 pythonc结论参考 SVD奇异值分解与PCA主成分分析 SVD动画图解–Wiki Eigen Svd 和 np.linalg.svd都可以用于SVD计算&#xff0c;但两者却存在细微的差别。 python import numpy as np datanp.array([[0.99337785, 0.08483806, 0.07747866, -92.91055059],[-0.07889607,…