C++动态内存管理

目录

  • C语言中的动态内存管理
  • C++动态内存管理
    • 动态管理内置类型
    • 动态管理自定义类型
  • new和delete的实现原理
    • operator new和operator delete函数
    • new和delete对内置类型的实现原理
    • new和delete对自定义类型的实现原理
  • malloc/free和new/delete区别

C语言中的动态内存管理

之前学习了C语言中的动态内存管理:C语言中动态内存管理

我们这里简单复习一下:
C语言中动态内存管理的函数:malloc,calloc,realloc,free

int main()
{int* p1 = (int*)malloc(sizeof(int) * 4);int* p2 = (int*)calloc(4, sizeof(int));int* p3 = (int*)realloc(p1, sizeof(int) * 10);free(p2);free(p3);
}

这里我们可以看出,C语言中开辟动态资源,需要类型强转,需要写入开辟具体的字节数
其实还不是很方便

所以C++内存管理解决了这个问题

C++动态内存管理

C++兼容C,所以malloc,calloc,realloc,free在C++中可以继续使用
C++提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理

动态管理内置类型

  • 动态申请一个int类型空间:
int* p1 = new int;

这里可以看出C++中开辟一个int类型,就直接在new后面写上int类型就可以,在C中,我们需要写入Int类型的大小

这里没有进行初始化,所以开辟出的空间里的是随机值

  • 动态申请一个int类型空间,并且初始化为3:
int* p2 = new int(3);

C++中,new的同时是可以初始化的,这是C语言中动态内存开辟中不具备的能力

  • 动态申请3个int类型空间:
int* p3 = new int[3];

这里没有进行初始化,所以开辟出的空间里的是随机值

  • 动态申请5个int类型空间,并且初始化:
int* p4 = new int[5] {1, 2, 3, 4, 5};
  • 释放空间
delete p1;
delete p2;
delete[] p3;
delete[] p4;

申请和释放单个元素的空间,使用newdelete操作符
申请和释放连续的空间,使用new[]delete[]操作符

newdelete配合,mallocfree配合使用,不要交叉混合使用


动态管理自定义类型

在申请自定义类型空间时,new会自动调用构造函数,delete会自动调用析构函数,而mallocfree不会
这也是new/delete和malloc/free最大的区别

现在有如下的类:

class A
{
public:A(int a = 0):_a(a){cout << "A(int a = 0)" << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};

用malloc和free管理一个自定义对象

int main()
{A* pa1 = (A*)malloc(sizeof(A));free(pa1);return 0;
}

可以看到没有任何输出,也就是不会自动调用构造函数和析构函数
在这里插入图片描述
接着用new/delete管理一个自定义对象

int main()
{A* pa1 = (A*)malloc(sizeof(A));free(pa1);A* pa2 = new A;delete pa2;return 0;
}

可以看到,结果有输出内容,也就说明new可以调用构造函数,delete会调用析构函数
在这里插入图片描述
因为有默认构造函数,所以A* pa2 = new A;这里自动按照默认构造函数赋值
在这里插入图片描述
如果没有默认构造函数,A* pa2 = new A;这样的写法会报错的
在这里插入图片描述

这时就需要传值

A* pa2 = new A(1);

开辟连续空间的自定义对象:

A* pa3 = new A[3]{ 1,2,3 };

上面这种写法会涉及到隐式类型转换,把int类型转成自定义类型

也可以使用匿名对象来进行初始化:

A* pa3 = new A[3]{ A(1),A(2),A(3) };

对于A* pa3 = new A[3]{ A(1),A(2),A(3) };这样开辟连续空间时,也会多次调用构造函数
同理delete[] pa3也会多次调用析构函数

在这里插入图片描述


new和delete的实现原理

operator new和operator delete函数

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

面向对象的语言处理失败,不喜欢用返回值,喜欢用抛出异常
所以malloc申请空间失败返回NULL,而new申请失败是抛出异常

operator new 对malloc进行封装,如果失败抛异常
所以operator new不是直接给我们用的,而是给new用的

同理operator delete是对free函数进行封装,同时如果失败抛出异常,operator delete 不是给我们用的,而是给delete用的

下面是operator new和operator delete函数的源码,的确可以看到对malloc和free的封装,以及检测异常的部分:

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 memorystatic const std::bad_alloc nomem;_RAISE(nomem);}
return (p);
}//operator delete: 该函数最终是通过free来释放空间的
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;
}

new和delete对内置类型的实现原理

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

new和delete对自定义类型的实现原理

在这里插入图片描述
new的原理:先调用operator new函数申请空间,再在申请的空间上执行构造函数,完成对对象的初始化
delete的原理:先调用析构函数,完成对对象中资源的清理工作,再调用operator delete函数

这里需要注意的是:new是先开空间再构造,而delete是先析构再释放空间,不要搞混

下面我们通过一个Stack类能够更好的理解:

class Stack
{
public:Stack(int capacity = 4, int top = 0):_capacity(capacity), _top(top){_a = new int[capacity];}~Stack(){delete[] _a;}private:int* _a;int _capacity;int _top;
};

在运行Stack* pst = new Stack语句时,只能先开辟一段空间,然后再调用构造函数malloc出一段空间给_a
在这里插入图片描述

接着在运行delete[] pst时,必须先调用析构函数。这里如果先释放空间,则是先释放在堆区中对象的空间,那么_a指向的空间没有释放,这里造成内存泄露
在这里插入图片描述
所以必须先用析构,将数组空间释放,再释放对象整体

其实除了operator new和 operator delete外,还有operator new[]和operator delete[]函数,这两个是用来开辟和释放连续空间的对象
new T[N]:调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的开辟,然后再执行N次构造函数
delete[]:先调用N次析构函数,完成对象中资源的清理,再调用operator delete[]释放空间,operator delete[]中是调用N次operator delete来释放空间


malloc/free和new/delete区别

  1. malloc和free是函数,new和delete是操作符
  2. malloc申请空间不可以初始化,new可以
  3. malloc返回值类型是void*,接收时需要强转,new不需要
  4. malloc申请空间时,需要手动计算开辟空间的大小,而new不需要,后面跟上空间类型就可以。多个对象时,在[]中指定对象个数即可,不用手动计算大小
  5. malloc失败后返回NULL,而new失败后会抛出异常
  6. 申请自定义类型对象时,malloc和free只会开辟和释放空间,不会调用构造和析构函数,而new/delete,申请空间后会调用构造函数,释放空间前会调用析构函数。

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

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

相关文章

Nginx系列之 一 负载均衡

目录 一、Nginx概述 1.1 负载均衡概述 1.2 负载均衡的作用 1.3 四/七层负载均衡 1.3.1 网络模型简介 1.3.2 四层和七层负载均衡对比 1.3.3 Nginx七层负载均衡实现 1.4 Nginx负载均衡配置 1.5 Nginx负载均衡状态 1.6 Nginx负载均衡策略 二、负载均衡实战 2.1 测试服…

算法通关村第一关——链表白银挑战笔记

文章目录 两个链表的第一个重合节点判断回文链表 两个链表的第一个重合节点 同LeetCode 160.相交链表 解法一&#xff1a;Hash和Set(集合&#xff09;&#xff0c;此处用Set合适。 把其中一个链表的所有节点引用放入set&#xff0c;再从头遍历另一个链表第一次重合的地方就是答…

Android性能优化之SharedPreference卡顿优化

下面的源码都是基于Android api 31 1、SharedPreference使用 val sharePref getPreferences(Context.MODE_PRIVATE) with(sharePref.edit()) { putBoolean("isLogin", true)putInt("age", 18)apply() } val isLogin sharePref.getBoolean("isLogi…

windows环境下docker数据迁移到其他盘

docker安装在C盘&#xff0c;使用一段时间后&#xff0c;C盘爆满。因此想把C盘中的数据迁移到其他盘&#xff0c;以释放C盘空间。分为以下步骤&#xff1a; 1、启动docker软件&#xff0c;打开PowerShell并切换到Docker Compose配置文件的目录。 Docker Compose配置文件的目录…

通过社区参与解锁早期增长:Maven 远程医疗平台概览

Maven通过用户导向的渐进式验证&#xff0c;找到了一个被忽视的巨大女性医疗服务市场&#xff0c;作为女性医疗保健的先行者&#xff0c;已服务超过1500万用户&#xff0c;目前估值已达$14亿。本文将深入探索Maven实现产品市场匹配的三个阶段&#xff0c;从如何验证初始的市场机…

Vue2基础十、Vuex

零、文章目录 Vue2基础十、Vuex 1、vuex概述 &#xff08;1&#xff09;vuex是什么 vuex 是一个 vue 的 状态管理工具&#xff0c;状态就是数据。大白话&#xff1a;vuex 是一个插件&#xff0c;可以帮我们管理 vue 通用的数据 (多组件共享的数据) 例如&#xff1a;购物车数…

Linux安装部署Nacos和sentinel

1.将nacos安装包下载到本地后上传到linux中 2.进入nacos的/bin目录,输入命令启动nacos [rootlocalhost bin]# sh startup.sh -m standalone注:使用第二种方式启动,同时增加日志记录的功能 2.2 startup.sh文件是不具备足够的权限,否则不能操作 给文件赋予执行权限 [rootlocalh…

【lesson5】linux vim介绍及使用

文章目录 vim的基本介绍vim的基本操作vim常见的命令命令模式下的命令yypnyynpuctrlrGggnG$^wbh,j,k,lddnddnddp~shiftrrnrxnx 底行模式下的命令set nuset nonuvs 源文件wq!command&#xff08;命令&#xff09; vim配置解决无法使用sudo问题 vim的基本介绍 首先vim是linux下的…

十、数据结构——链式队列

数据结构中的链式队列 目录 一、链式队列的定义 二、链式队列的实现 三、链式队列的基本操作 ①初始化 ②判空 ③入队 ④出队 ⑤获取长度 ⑥打印 四、循环队列的应用 五、总结 六、全部代码 七、结果 在数据结构中&#xff0c;队列&#xff08;Queue&#xff09;是一种常见…

react-router-dom和react-router的区别

react-router-dom和react-router的区别 前言 在使用react-router-dom的时候&#xff0c;经常会和react-router搞混了&#xff0c;搞不清楚它们哪个跟哪&#xff0c;到底有什么关系&#xff0c;今天来总结一下。 结论 react-router-dom是在react-router的基础上开发的&#…

变现:利用 chatgpt + midjourney 制作微信表情包

1、利用gpt生成提示词&#xff0c;当然也可以直接翻译 生成基础提示词&#xff0c; 比如&#xff1a; an anime image with a white kawaii character in it, in the style of light green and brown, minimalist detail, animated gifs, cranberrycore, 1860–1969, babyco…

C#实现数字验证码

开发环境&#xff1a;VS2019&#xff0c;.NET Core 3.1&#xff0c;ASP.NET Core API 1、建立一个验证码控制器 新建两个方法Create和Check&#xff0c;Create用于创建验证码&#xff0c;Check用于验证它是否有效。 声明一个静态类变量存放列表&#xff0c;列表中存放包含令…

python selenium爬虫自动登录实例

拷贝地址&#xff1a;python selenium爬虫自动登录实例_python selenium登录_Ustiniano的博客-CSDN博客 一、概述 我们要先安装selenium这个库&#xff0c;使用pip install selenium 命令安装&#xff0c;selenium这个库相当于机器模仿人的行为去点击浏览器上的元素&#xff0…

Android ANR触发机制之Service ANR

一、前言 在Service组件StartService()方式启动流程分析文章中&#xff0c;针对Context#startService()启动Service流程分析了源码&#xff0c;其实关于Service启动还有一个比较重要的点是Service启动的ANR&#xff0c;因为因为线上出现了上百例的"executing service &quo…

R-并行计算

本文介绍在计算机多核上通过parallel包进行并行计算。 并行计算运算步骤&#xff1a; 加载并行计算包&#xff0c;如library(parallel)。创建几个“workers”,通常一个workers一个核&#xff08;core&#xff09;&#xff1b;这些workers什么都不知道&#xff0c;它们的全局环…

c++学习(位图)[22]

位图 位图&#xff08;Bitmap&#xff09;是一种数据结构&#xff0c;用于表示一个固定范围的布尔值&#xff08;通常是0或1&#xff09;。它使用一个二进制位来表示一个布尔值&#xff0c;其中每个位的值表示对应位置的元素是否存在或满足某种条件。 位图可以用于解决一些特…

利用MATLAB制作DEM山体阴影

在地理绘图中&#xff0c;我们使用的DEM数据添加山体阴影使得绘制的图件显得更加的美观。 GIS中使用ArcGIS软件就可以达到这一目的&#xff0c;或者使用GMT&#xff0c;同样可以得到山体阴影的效果。 本文提供了一个MATLAB的函数&#xff0c;可以得到山体阴影。 clear all;c…

《面试1v1》如何能从Kafka得到准确的信息

&#x1f345; 作者简介&#xff1a;王哥&#xff0c;CSDN2022博客总榜Top100&#x1f3c6;、博客专家&#x1f4aa; &#x1f345; 技术交流&#xff1a;定期更新Java硬核干货&#xff0c;不定期送书活动 &#x1f345; 王哥多年工作总结&#xff1a;Java学习路线总结&#xf…

安防视频管理平台GB设备接入EasyCVR, 如何获取RTMP与RTSP视频流

安防视频监控平台EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安防视频监控的能力&#xff0c;比…

基于粒子群优化算法的分布式电源选址与定容【多目标优化】【IEEE33节点】(Matlab代码实现)

目录 &#x1f4a5;1 概述 1.1 目标函数 2.2 约束条件 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f308;4 Matlab代码实现 &#x1f4a5;1 概述 分布式电源接入配电网&#xff0c;实现就地消纳&#xff0c;可以提高新能源的利用率、提高电能质量和降低系统网损…