转自:https://blog.csdn.net/Code_beeps/article/details/89625473#comments

首先我们看看 c 语言是如何进行动态内存分配的;
c 语言主要是使用malloc / calloc / realloc 来进行内存申请的。
malloc / realloc / calloc三者的共同点与不同点:

共同点

都是从堆上进行动态内存分配
释放内存都是需要使用free函数来释放
三者的返回值都是void*
都需要强制类型转换
都需要对申请出的空间判空(因为申请内存失败会返回空)

不同点:
1)void *malloc( size_t size );
malloc的参数是用户所需内存空间大小的字节数,不会对申请成功的内存初始化。
malloc 申请空间时并不是需要多少就申请多少,而是会多申请一些空间,1)多申请一个32字节的结构体,里面对申请的空间进行描述,2)在申请的空间前后会各多申请 4 个字节的空间,这就是保护机制,当你操作不当越界了,这 8 个字节的内容会改变,操作系统会检查前后 4 个字节是否改变了,以此判断是否越界了。



2)void *calloc( size_t num, size_t size );
calloc的参数:第一个:元素的个数,第二个:单个元素所占字节;会把申请成功的空间初始化为 0

3)void *realloc( void *ptr, size_t size );
realloc的参数:第一个:地址,第二个:字节数
  对于 realloc 的第一个参数:
    如果指向空,那么此时realloc 就和 malloc 是一样的;
    如果不为空,那么就将即将要申请的空间与原空间进行比较。
        如果要申请的空间比原空间小,就将原空间缩小,并返回原空间首地址
        如果要申请的空间比原空间大,那么分两种情况:
        第一种:新旧空间之差小于原空间大小,直接在原空间进行延伸,并返回原空间的首地址。
        第二种:新旧空间之差大于原空间的大小,那么直接开辟新空间,并将原空间的数据拷贝到新空间,并返回新空间首地址。

看完了 C 动态内存管理,那么来看看C++的动态内存管理:
首先 C 语言中的动态内存管理方式在 C++ 中仍然可以使用。c++ 中多了 new 这个操作符。
new申请的空间:

1、不用强制类型转换;
2、不用对申请出来的空间进行判空;
3、可以申请时初始化这段空间。

malloc / new / new[] 和 free / delete / delete[]
对于内置类型:如果没有配合使用,可能不会出现什么问题。
对于自定义类型:
  malloc:只是将空间动态开辟成功,并不会调用构造函数初始化空间。
  free:只是将申请的空间进行释放,并不会调用析构函数清理对象中的资源

new:先将对象的空间开辟成功,然后调用构造函数完成对象的初始化。
  delete:先调用析构函数将对象中的资源清理,然后释放对象占用的空间
如果对一个内部有资源的自定义类型使用 malloc 开辟内存,此时调用 delete 进行空间的释放,程序就会崩溃。因为 malloc 只负责开辟空间,并不会调用对象的构造函数对其成员变量进行初始化,那么内部的成员变量是没有分配空间的,当我们调用 delete 时,delete会先对对象进行资源清理,但是对象里的资源 malloc 并没有给其分配,所以我们清理的时候是非法的操作。导致程序崩溃。

对于内部有资源的自定义类型,使用 new 开辟的空间使用 free 释放,会造成内存泄漏,因为 free 并不会调用析构函数清理对象的资源,因此会造成资源泄漏。

new底层的流程:

第一步:调用operator new() 来申请空间
第二步:调用该类的构造函数

operator new() 的工作流程:
比如 new T:底层调用 void* operator new(sizeof(T)),申请 T 类型大小的堆空间。
  在这个函数中是循环调用 malloc :

  1、申请空间成功:返回空间的首地址。2、申请空间失败:检测用户是否提供空间不足的应对措施?如果提供应对措施,则执行应对措施,否则直接抛出 bad_alloc 类型的异常。


new[]的流程:
第一步:调用void* operator new[](count = sizeof(T) * N + 4),如果T类的析构函数显式提供就多申请4个字节。(多申请的四个字节就是用来保存对象的个数,可以知道未来需要调用几次析构函数。)
  这里operator new 的运行流程和上图一致。
第二步:将空间前四个字节填充对象的个数,然后调用构造函数构造 N 个 T 类型对象。

delete的流程:
第一步:调用析构函数清理对象中的资源。
第二步:调用void operator delete(void* p)释放空间,void operator delete(void* p)中调用的是 free 释放空间。

delete[] 的流程:
第一步:从第一个对象空间之前的4个字节中取对象的个数N
第二步:调用N次析构函数倒着释放(栈的特性)
第三步:void operator delete[](void* p)----这个p就是真正使用位置倒退4个字节的位置,也就是申请的空间的首地址。
在这里operator delete[](void* p) 调用 void operator delete(void* p) 调用 free()

综上:operator new 和 operator delete 实际上是由 malloc 和 free 来实现的,是对malloc 和 free 的封装。

malloc/free 和 new/delete 区别:
共同点:都在堆上申请空间,都需要手动申请 / 释放空间。
不同点:

  1)malloc/free 是函数,new/delete是标识符2)malloc 不会对对象进行初始化,new 可以初始化3)malloc 申请空间时,需要手动计算需要申请空间的大小,而new只需在后面跟上类型,编译器会自动计算大小。4)malloc 返回值是 void*,使用时必须要强制类型转换,而 new 并不需要强制类型转换,因为new后跟的就是类型。5)malloc 申请空间失败返回 NULL,因此使用时必须判空,new不需要判空,但是需要捕获异常6)申请自定义类型对象时,malloc/free只会开辟空间,并不调用构造/析构函数,而 new 是先申请空间,然后调用构造函数完成对象的初始化,delete 在释放空间前会先清理对象占用的资源。7)malloc/free 的效率会比 new/delete 的高,因为 new/delete 中封装的是malloc/free。

C/C++ 动态内存分配相关推荐

  1. 释放变量所指向的内存_C++动态内存分配(学习笔记:第6章 15)

    动态内存分配[1] 动态申请内存操作符 new new 类型名T(初始化参数列表) 功能: 在程序执行期间,申请用于存放T类型对象的内存空间,并依初值列表赋以初值. 结果值: 成功:T类型的指针,指向 ...

  2. 动态内存分配与柔性数组

    什么时动态内存分配 一般我们写程序都是在栈区分配空间,如果我们想根据需求想随时存放随时释放数据,堆区可以实现根据需求想系统申请所需大小的空间. 建立内存的动态分配 内存的动态分配是通过系统提供的函数来 ...

  3. C++中的动态内存分配

    1.Cpp中的内存分配 了解动态内存在C++中是如何工作的是成为一名合格的C++程序员必不可少的.C++程序中的内存分为两个部分: 栈:在函数内部声明的所有变量都将占用栈内存. 堆:这是程序中未使用的 ...

  4. 【 C 】动态内存分配实用案例(二)之复制字符串

    用动态分配内存制作一个字符串的一份拷贝.注意:调用程序应该负责检查这块内存是否分配成功,这样做允许程序以任何它所希望的方式对错误作出反应. #nclude <stdlib.h> #incl ...

  5. 【 C 】动态内存分配实用案例(一)之读取、排序和打印一列整形值

    什么时候用动态内存分配呢?下面这个案例给出了一个比较实用且精彩地使用动态内存的场合,并且教你如何合理地使用动态内存分配? 动态内存分配一个常见的用途就是为那些长度在运行时才知的数组分配内存空间. 下面 ...

  6. 【 C 】动态内存分配案例分析

    声明一个指向char类型的指针,可以在声明的时候就对其进行初始化,这样是合理的. 例如: E1: #include <stdio.h> #include <stdlib.h> ...

  7. 【C 语言】内存管理 ( 动态内存分配 | 栈 | 堆 | 静态存储区 | 内存布局 | 野指针 )

    相关文章链接 : 1.[嵌入式开发]C语言 指针数组 多维数组 2.[嵌入式开发]C语言 命令行参数 函数指针 gdb调试 3.[嵌入式开发]C语言 结构体相关 的 函数 指针 数组 4.[嵌入式开发 ...

  8. 从更底层研究C\C++动态内存分配

    2019独角兽企业重金招聘Python工程师标准>>> 以前在学C++ 的时候,一直不懂:动态内存分配的本质,或者更加深入到底层的意义.虽然说,动态内存分配就是,随机在内存中分配一个 ...

  9. 静态、动态内存分配比较

    首先,在使用动态分配内存技术前,必须明白自己在做什么,这样做与其它的方法有什么不同,特别是会产生哪些负面影响,天下没有免费的午餐.动态分配内存与静态分配内存的区别: 1) 静态内存分配是在编译时完成的 ...

  10. 动态内存分配到底为谁分配内存空间【浅谈动态内存的一个实例】

    为了动态的管理宝贵的内存,许多程序中要使用到动态内存分配.一般情况下,在c语言中,使用malloc()函数来分配指定大小的内存空间,用free()函数来释放这块内存空间.但是,往往初学者在编写这类程序 ...

最新文章

  1. 利用python实现Windows8定时自动关机和休眠
  2. 超越Facebook、谷歌、微软,百度发布全球首个百亿参数对话预训练生成模型PLATO-XL...
  3. android 9.0室内定位方案,Android GPS室内定位问题的解决方法(location为null)
  4. java 静态初始化 调用_java JVM-类加载静态初始化块调用顺序
  5. 百度云获取外链直接下载突破限速
  6. 我的世界——用一桶水一直灭岩浆一直刷黑曜石
  7. Ubuntu 19.04 Beta 发布,正式版定于 4 月
  8. 详细整理分层开发步骤!
  9. tf.layers.dropout
  10. 4章 关键的“构建”决策
  11. 51单片机复习:外部中断,定时器/计数器中断
  12. 使用crontab不能正常执行的问题
  13. IntelliJ IDEA 创建 maven 创建java web 项目
  14. minecraftjava版光追_我的世界:光追技术终于开始测试?没想到网易版已更新狐狸生物?...
  15. mysql软件字体模糊_Windows 10字体模糊发虚! 如何解决?
  16. php获取qq音乐的api类,利用QQ音乐api集成的php歌曲搜索
  17. php网页读取sql数据库数据模板,discuz模板中直接读取数据库中的插件数据
  18. android通话模块详解
  19. Guided backpropagation
  20. 看井上雄彦是如何作画的!

热门文章

  1. 华为离职副总裁徐家骏:年薪千万的工作感悟
  2. linux localhost识别,linux之localhost127.0.0.1及本机地址的差别
  3. C语言多线程的应用--局域网中多台计算机对同一文件读写
  4. JavaFx+JxBrowser实现快速开发
  5. 【UDS】ISO14229之0x3E服务
  6. Anaconda创建、激活、退出、删除环境及管理环境中的包相关命令——最新全面直观版
  7. matlab布尔代数,数学布尔表达式
  8. 苹果电容笔和普通电容笔的区别有哪些?Ipad10代平价电容笔推荐
  9. 关于-fPIC, -fpic, -fpie, -fPIE的一点理解
  10. 国家职称计算机中级考试报名时间,中级职称计算机考试_报名时间_考试内容_科目_题库_教材_爱考学...