深入理解C++系列(05)——C++的内存管理

发布时间:2026/7/29 5:00:40
深入理解C++系列(05)——C++的内存管理 文章目录上期回顾C/C 内存管理一、本讲核心主线二、C/C 内存分布三、典型变量位置判断四、回顾一下C 语言动态内存管理1. malloc2. calloc3. realloc4. free五、C 动态内存管理new/delete⭐️⭐️⭐️1. 操作内置类型2. 操作自定义类型**知识点总结**六、operator new 和 operator delete七、new/delete 实现原理1. 内置类型2. 自定义类型的 new 原理3. 自定义类型的 delete 原理4. new T[N] 原理5. delete[] 原理八、定位 newplacement new⭐️⭐️九、malloc/free 和 new/delete 的区别十、易错点汇总下期预告模版初阶结语◆ 博主此生决int分享编程知识深挖底层原理持续原创更新热门专栏深入理解 C系列|算法系列快速复习系列 |Java 速通系列 本系列知识点前后关联较强建议按照专栏顺序阅读哦本系列主要面向的阅读人群1学完 C 语言准备系统学习 C 的同学2已经学习过 C希望重新梳理知识体系的同学3想深入理解 C 设计思想与底层原理而不仅仅停留在语法层面的同学不止教你会写代码更带你理解代码为什么这样设计---上期回顾hello大家好这里是此生决int上一期我们终于结束了面向对象的语音C的一个重要组成部分——类和对象今天我们就一起来看看变量在C里面是怎么存储的吧看看他相较于C语言有哪些改进之处C/C 内存管理一、本讲核心主线这一讲主要解决三个问题C/C 程序中的变量分别存在哪里C 和 C 分别如何动态申请和释放堆空间malloc/free和new/delete到底有什么区别一句话总结malloc/free只负责堆空间申请和释放new/delete除了申请和释放空间还会对自定义类型自动调用构造函数和析构函数。二、C/C 内存分布常见内存区域区域存放内容栈非静态局部变量、函数参数、返回值等堆程序运行时动态申请的空间数据段 / 静态区全局变量、静态变量代码段 / 常量区可执行代码、只读常量、字符串常量内存映射段动态库映射、共享内存等了解即可三、典型变量位置判断intglobalVar1;staticintstaticGlobalVar1;voidTest(){staticintstaticVar1;intlocalVar1;intnum1[10]{1,2,3,4};charchar2[]abcd;constchar*pChar3abcd;int*ptr1(int*)malloc(sizeof(int)*4);}重点结论名称所在区域原因globalVar数据段 / 静态区全局变量staticGlobalVar数据段 / 静态区静态全局变量staticVar数据段 / 静态区静态局部变量localVar栈普通局部变量num1栈局部数组整体在栈上char2栈局部字符数组整体在栈上*char2栈数组元素在数组内部pChar3栈局部指针变量本身在栈上*pChar3代码段 / 常量区指向字符串常量ptr1栈局部指针变量本身在栈上*ptr1堆malloc申请的空间最容易错的是后面学string类如果不懂那就是没有理解这里charchar2[]abcd;// 字符数组内容拷贝到栈上constchar*pChar3abcd;// 指针在栈上字符串常量在常量区图示四、回顾一下C 语言动态内存管理C 语言中常用malloc calloc realloc free1.mallocint*p(int*)malloc(sizeof(int)*4);特点在堆上申请指定字节数的空间。不初始化申请到的空间。返回void*C 中需要强转。申请失败返回NULL。注释1一般都要强转但C语言存在隐式类型转换C不支持所以必须这样写int*p(int*)malloc(sizeof(int)*4);2.callocint*p(int*)calloc(4,sizeof(int));特点申请4个int大小的空间。会把空间初始化为0。3.reallocint*p2(int*)realloc(p1,sizeof(int)*10);//注释1特点调整原动态内存块大小。可能原地扩容也可能重新开空间并拷贝旧数据。返回新地址。注意int*p3(int*)realloc(p2,sizeof(int)*10);free(p3);这里不需要再free(p2)因为realloc成功后应以返回的新指针为准。注释1这里可以写成这样吗p1(int*)realloc(p1,sizeof(int)*10);//注释1不行realloc 如果失败会返回 NULL但不会释放原来的内存。如果直接使用prealloc(p,size);会导致原指针被 NULL 覆盖从而丢失原内存地址最终造成内存泄漏。4.freefree(p);特点释放堆空间。只释放空间不会调用析构函数。注释1注释1例如free类类型他只会释放对应的空间而不会调用类类型的析构函数。总之只需要记住malloc/free、new/delete、new[]/delete[] 一一对应不能混用。就没有什么问题具体的后面标题2操作自定义类型会讲到五、C 动态内存管理new/delete⭐️⭐️⭐️C 中推荐使用newdeletenew[]delete[]1. 操作内置类型int*p1newint;//int*p1定义一个int指针new int堆上申请一个int大小的空间但是没有初始化int*p2newint(10);int*p3newint[3];deletep1;deletep2;delete[]p3;注意匹配一定要匹配使用。申请释放newdeletenew[]delete[]2. 操作自定义类型classA{public:A(){coutA()endl;}~A(){cout~A()endl;}};A*pnewA;deletep;核心区别new A申请空间 调用构造函数。delete p调用析构函数 释放空间。而A*p(A*)malloc(sizeof(A));free(p);只会申请和释放空间不会调用构造和析构。我的理解A* p new A;既申请了空间又创建了对象调用了构造函数delete p;他既调用了析构函数又释放了空间A* p (A*)malloc(sizeof(A)); 和free§;只是申请了空间没有创建对象也没有调用构造和析构函数知识点总结free 只负责释放 malloc 申请的那块原始内存不会调用对象的析构函数因此对象内部管理的资源不会被自动释放。new/delete 不仅负责内存申请和释放还负责构造函数和析构函数的调用所以 C 中管理类对象通常使用 new/delete。同时需要保证 malloc/free、new/delete、new[]/delete[] 一一对应不能混用。六、operator new和operator delete重点区分名称本质new操作符用户使用delete操作符用户使用operator new全局函数底层负责申请空间operator delete全局函数底层负责释放空间new的底层会调用operator new。delete的底层会调用operator delete。大致关系new - operator new - malloc delete - operator delete - freeoperator new申请失败时通常会抛出bad_alloc异常而不是像malloc那样返回NULL。七、new/delete实现原理1. 内置类型对于内置类型差别相对较小。int*p1(int*)malloc(sizeof(int));int*p2newint;主要区别malloc失败返回NULL。new失败抛异常。new写法更简单不用手动计算字节数和强转。2. 自定义类型的new原理A*pnewA(10);步骤调用operator new申请空间。在申请到的空间上调用构造函数完成对象构造。3. 自定义类型的delete原理deletep;步骤调用析构函数清理对象内部资源。调用operator delete释放对象空间。4.new T[N]原理A*pnewA[10];步骤调用operator new[]申请连续空间。实际底层会调用operator new。对 N 个对象分别调用构造函数。5.delete[]原理delete[]p;步骤对 N 个对象分别调用析构函数。调用operator delete[]释放空间。实际底层会调用operator delete。八、定位 newplacement new⭐️⭐️定位new的作用在已经分配好的原始内存空间上调用构造函数初始化对象。格式new(place_address)Type;new(place_address)Type(initializer-list);//Type(初始化列表);示例A*p(A*)malloc(sizeof(A));//申请空间new(p)A(10);//指定空间创建对象并调用构造函数p-~A();//指定空间调用析构函数free(p);//释放空间解释malloc只申请一段原始空间还不是对象。new(p) A(10)在这段空间上调用构造函数。p-~A()显式调用析构函数。free(p)释放空间。使用场景了解常和内存池配合使用。内存池只提供原始内存自定义类型对象还需要显式构造。九、malloc/free和new/delete的区别共同点都是从堆上申请空间都需要用户手动释放。区别对比项malloc/freenew/delete本质函数操作符空间大小手动计算字节数根据类型自动计算返回类型void*C 中需强转返回对应类型指针初始化malloc不初始化calloc清零new可以初始化失败处理返回NULL抛异常自定义类型不调用构造 / 析构自动调用构造 / 析构数组申请手动算总大小new[]指定对象个数释放方式freedelete/delete[]最重要区别对自定义类型new/delete会调用构造函数和析构函数malloc/free不会。十、易错点汇总char arr[] abcd的内容在栈上const char* p abcd指向常量区。指针变量本身在哪里看它怎么定义它指向哪里看它保存的地址来自哪里。malloc申请失败返回NULLnew失败抛异常。new/delete要配对new[]/delete[]要配对。malloc/free不会调用构造和析构。operator new不是new操作符本身而是底层申请空间的函数。定位new只调用构造函数不负责申请空间。用定位new构造的对象需要手动调用析构函数。下期预告模版初阶结语本文到此结束感谢大家的阅读如果觉得本文对你有所帮助欢迎点赞、收藏、关注也欢迎在评论区一起交流讨论。也欢迎订阅我的深入理解 C系列从语法入门到底层原理系统掌握现代 C算法系列从入门到精通蓝桥杯、ACM、LeetCode 与面试算法全路线快速复习系列知识梳理、查漏补缺考前冲刺必备Java 速通系列已学 C 语言快速上手 Java轻松备战期末考试愿每一次敲下键盘都比昨天更进一步愿每一行代码落下都让未来多一种可能