C++入门全集(5):内存管理

前言

一、内存区域划分

二、C++的内存管理方式

2.1 对内置类型

2.2 对自定义类型

三、new和delete的底层实现

四、new和delete的原理

五、定位new

六、malloc/free和new/delete

 

前言

在C++中,内存管理是不可避免的一门必修课。C++对内存的自由度使其获得了更高的性能,以及更高的难度。内存泄漏往往是每个C++学习者绕不开的错误, 而内存管理的水平高低也能看出一个编程者的能力。

在C语言中,我们学习了malloc、calloc、realloc和free,对C语言的内存管理也有了大致的接触。

本文中我们来学习C++中的内存管理


一、内存区域划分

C++中,程序的内存区域从低地址到高地址划分如下:

  • 代码段:存储可执行程序的代码和只读常量
  • 数据段:存储已初始化的全局变量和静态变量
  • 堆:用于程序运行时动态内存分配,从低地址向高地址增长
  • 栈:又叫堆栈,存储非静态局部变量/函数参数和返回值等,从高地址向低地址增长

例如: 

globalVar是全局变量,staticGlobalVar是静态全局变量,存储在数据段中;

staticVar是静态局部变量,存储在数据段中;

localVar、num1、char2、pChar3和ptr1都是局部变量,存储在栈中;

*char2是在栈帧中的空间,存储在栈中;*pChar3是常量字符串abcd的第一个字符,在代码段中;

malloc动态开辟出的空间存储在堆上。


二、C++的内存管理方式

2.1 对内置类型

C++兼容C语言,所以C语言的内存管理方式在C++中可以正常使用

相比C语言使用malloc和free等函数进行内存管理,C++提出了自己的内存管理方式:通过newdelete操作符进行动态内存管理

以上是C语言和C++动态申请一个类型大小的空间、多个类型大小的空间和内存释放的方式

 

实际上,面对内置类型,用malloc和new没有本质的区别,最大的区别在于:new可以初始化

在默认情况下,new和malloc一样不会对内置类型进行初始化,但是我们可以提出需求

注意区分初始化和申请多个元素,一个是圆括号一个是方括号

我们new一个数组时也可以进行初始化,例如:

C++不推荐使用malloc和free,我们最好使用new和delete,并且记得务必匹配使用。

对于内置类型,malloc和new区别不大。new是为了自定义类型而生的。

2.2 对自定义类型

我们在创建自定义类型对象的时候,需要调用析构函数,销毁时需要调用构造函数

而如果我们使用malloc和free的话,是不会调用这两个函数的

使用new来为自定义类型对象申请空间,编译器才会调用构造函数为对象初始化;用delete为自定义类型对象释放空间,才会调用析构函数。


三、new和delete的底层实现

new和delete并不是函数,而是用户进行动态内存申请和释放的操作符

但是其底层还是需要调用函数。

new在底层调用operator new这个函数来申请空间,delete在底层调用operator delete函数来释放空间。operator new和operator delete是系统提供的全局函数。

注意:这两个函数不是new和delete的重载函数!!!

虽然函数名中带operator,但并不是重载函数,具有很强的误导性。

我们来看看这两个函数的实现:

void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{// try to allocate size bytesvoid* 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);
}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_FINALLYreturn;
}

通过上面两个全局函数的实现,可以看出operator new实际上也是通过malloc来申请空间的,如果malloc申请空间成功就直接返回,如果失败则执行用户提供的应对措施,如果用户提供该措施则继续申请空间,否则抛出异常。

operator delete最终也是通过free来释放空间的。就像引用的底层也是用指针的方式实现的。

需要注意,构造函数和析构函数不是通过这两个函数来调用的。 


四、new和delete的原理

(1)new的原理

  • 调用operator new函数申请空间
  • 在申请的空间上执行构造函数,完成对象的构造

(2)delete的原理

  • 在空间上执行析构函数,完成对象中资源的清理工作
  • 调用operator delete函数释放对象的空间

(3)new T[N]的原理

  • 调用operator new[]函数,而operator new[]函数实际上又会调用operator new函数完成N个T类型对象的空间申请
  • 在申请的空间上执行N次构造函数

(4)delete[]的原理

  • 在空间上执行N次析构函数,完成N个对象的资源清理
  • 调用operator delete[]函数,而operator delete[]函数又会调用operator delete函数来释放空间


五、定位new

定位new表达式用于在已分配的原始内存空间调用构造函数初始化一个对象

大部分情况下,我们直接使用new来给对象分配空间

但是有时候需要进行性能优化,我们会直接从内存池中拿空间,使用malloc开空间

平时我们需要分配空间时从操作系统——堆上开空间,每次有需求就要开一次,但是内存池一次从堆上拿走一个内存块(大块空间),就不需要我们重复的去申请,减少了与堆的交互,提升了效率

如果是自定义的对象,对于malloc出来的空间,则需要使用定位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不需要
  5. malloc申请空间失败时返回空指针,需要判空,new失败时抛出异常,需要捕获
  6. 为自定义类型对象申请空间时,malloc和free不会调用构造函数和析构函数,而new和free会调用

如果文章有误,欢迎在评论区指出

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

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

相关文章

单片机的boot升级和双备份升级

同时boot升级还会有一个策略来防止单片机变成砖:就是boot的升级程序写在boot中,这个部分的的升级程序是不会改动的,如果检测到升级失败,会一直等待,直到升级正确的程序

Sora: 大型视觉模型背景、技术、局限性和机遇的综述

论文链接:https://arxiv.org/pdf/2402.17177.pdf 背景 在分析 Sora 之前,研究者首先盘点了视觉内容生成技术的沿袭。 在深度学习革命之前,传统的图像生成技术依赖于基于手工创建特征的纹理合成和纹理映射等方法。这些方法在生成复杂而生动…

全自动气象站的工作原理

TH-CQX5全自动气象站是一款野外高精度监测气象数据的环境气象站设备。它结合了先进的传感器技术、自动化控制系统和远程通信技术,能够提供准确、实时的气象数据,为环境保护、气象研究、农业生产等领域提供重要的数据支持。 高精度传感器:全自…

苹果电脑安装Android Studio和配置SDK

大家好,我是你们的好朋友咕噜铁蛋!今天,我们要来聊一聊关于《苹果电脑安装Android Studio和配置SDK》这个话题。对于使用苹果电脑的开发者来说,安装Android Studio并配置SDK可能会有些不同,但只要跟着我的指引&#xf…

2024-3-5 python 序列小知识点

1、for循环的变量作用域不限于for循环内 >>>i 10 >>>for i in range(100): >>> print(i) >>> i 100此处,for循环里的 i 修改了之前的 i 变量的值。 2、列表推导式里的变量作用域仅限于推导式内 推导式犹如一个函数&…

五、布局布线约束、系统优化参数、时序优化收敛 关键技术点

在实际的工程当中,出现了时序违例的情况如何解决呢? 本章内容将介绍例外约束、布局布线的具体操作,实现系统参数的优化。 **前言:**通过约束时钟,比如基准时钟,和生成时钟,让我们的综合工具知道我们的时序…

嵌入式系统是什么?Linux应用开发是开发什么的?

第一篇: 原文链接:https://www.zhihu.com/question/464205608/answer/3358027187 一、什么是嵌入式系统 嵌入式系统是以应用为中心,以计算机技术为基础,软硬件可裁剪,适用于应用系统,对功能、可靠性、…

Redis之事务(详细解析)

请直接看原文:不能回滚的Redis事务还能用吗 - 知乎 (zhihu.com) ------------------------------------------------------------------------------------------------------------------------------ 1、Redis事务的概念: Redis 事务的本质是一组命令的集合。…

Linux编程3.3 进程-进程的终止

1、正常终止 从main函数返回调用exit(标准C库函数)调用_exti或_Exit(系统调用)最后一个线程从其启动例程返回最后一个线程调用 pthread exit 2、异常终止 调用abort接受到一个信号并终止最后一个线程对取消请求做处理响应 3、进程返回 通常程序运行…

电子邮件营销的优势包括?邮件营销的利弊?

电子邮件营销的优势及特点?电子邮件营销策略的好处? 电子邮件营销不仅是一种经济高效的营销方式,更是企业与潜在客户之间建立长期关系的桥梁。那么,电子邮件营销的优势具体有哪些呢?接下来,让蜂邮EDM来探讨…

【Web安全靶场】upload-labs-master 1-21

upload-labs-master 其他靶场见专栏… 文章目录 upload-labs-masterPass-01-js前端校验Pass-02-MIME校验Pass-03-其他后缀绕过黑名单Pass-04-.hatccess绕过Pass-05-点空格点代码逻辑绕过Pass-06-大小写绕过Pass-07-空格绕过Pass-08-点号绕过Pass-09-::$DATA绕过Pass-10-点空格…

【Redis】Redis持久化模式AOF

目录 引言 AOF持久化模式​编辑​编辑 AOF与RDB的混合持久化(4.x后的新特性) AOF的优缺点 修复破损aof文件 到底用RDB还是AOF 引言 AOF就相当于上面的日志形式。是追加式备份。所有发生的写操作,新增啊,修改啊,删除啊,这些命…

pdf电子准考证查询下载系统(实证效果可照片)V1.0

CSDNpdf电子准考证查询下载系统(实证效果可照片)V1.0 使用场景: 教育机构比如学校用pdf准考证查询下载系统(实证效果可照片,最适合准考证打印); 也可自定义图片及坐标用于各种优秀党员三好学生等荣誉证书、聘书授权代理pdf电子证书查询与下载。 推荐Linux PHP5.5-7.3使用使…

第七篇 - 人工智能与机器学习技术VS量测(Measurement)- 我为什么要翻译介绍美国人工智能科技巨头IAB公司 - 它是如何赋能数字化营销生态的?

IAB平台,使命和功能 IAB成立于1996年,总部位于纽约市。 作为美国的人工智能科技巨头社会媒体和营销专业平台公司,互动广告局(IAB- the Interactive Advertising Bureau)自1996年成立以来,先后为700多家媒…

鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:鼠标光标控制)

控制鼠标光标的显示样式。 说明: 从API Version 11开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 cursorControl setCursor setCursor(value: PointerStyle): void 方法语句中可使用的全局接口,调用此接口可以更…

增肌_锻炼

目录 练第一步 有氧运动关节活动度 第二步 脊柱侧弯吃 练 https://www.bilibili.com/video/BV14v4y1G7A3 第一步 有氧运动 有氧运动锻炼心肺 最大心率保持在50% - 60% 关节活动度 髋关节活动 亚足背屈   绕肩,肩环绕肩   第二步 高频的中等强度&#xf…

ubuntu_定制文件系统[2]-清理日志log

1.问题现象 系统长时间运行, 产生大量的系统日志 ubuntu/debian 系统日志如下 /var/log$ du -sh * 31M syslog # syslog日志 61M syslog.1 2.5G journal/ # systemd service日志 当日志文件过大, 硬盘空间占用100%时, 导致各种异常 命令按tab补全无响应服务/进程启动异常服务…

Google Play上架:自查封号政策解析(高风险行为之不允许破坏Google Play生态系统中用户信任度的应用或应用内容)

本文章提供给近期被封号的开发者们,希望能带来帮助,有其他的自查方向后续也会发布出来。 ——————————————————————————————————————— 用户数据设备和网络滥用 用户数据 设备和网络滥用

redis 缓存击穿问题(互斥锁,逻辑过期)

1、缓存击穿问题 缓存击穿问题:一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。 场景:假设线程1在查询缓存之后,本来应该去查询数据库,然后把这个数据重新加…

堆以及堆的实现

文章目录 堆的概念堆的实现HeapPushHeapPop HeapTop HeapSize HeapEmpty堆的应用 堆的概念 堆是一颗完全二叉树每个结点的值都小于子结点的值,这颗二叉树为小根堆每个结点的值都大于子结点的值,这颗二叉树为大根堆堆的定义如下:n个元素的序列…