【C++】new/delete 还是 malloc/free?C++内存管理的“世纪抉择
目录
一,计算机的内存的存储
1,内存划分
2,类型的判断
3,C语言中的动态内存管理
二,C++当中的内存管理方式
1,new和delete的使用
2,new和delete的底层实现原理
3,定位new表达式
三,总结 :malloc/free和new/delete之间的区别
一,计算机的内存的存储
1,内存划分
首先看下面这张图,这张图片展示了C/C++程序内存区域的各个部分:
栈的内存由高到低进行开辟,而堆的内存由低到高进行开辟。
内存空间在不同位下的效果:
2,类型的判断
globalvar:全局变量在静态区
staticGlobalvar:静态全局变量也在静态区
这两个的核心区别就是:全局变量可以在这个工程下的其他文件中进行使用,但是静态修饰的变量只能在当前文件下进行使用。
staticvar:静态的局部变量也在静态区
localvar/num1/char2:局部变量和数组都在栈中
*char2:表示首元素,依旧在栈中
pchar3:常量字符串指针,在栈中
*pchar3:表示常量字符串,在代码段当中
ptr1:表示开辟空间的指针,在栈中
*ptr1:表示开辟的空间,在堆中
3,C语言中的动态内存管理
在学习C++中的内存管理函数之前,需要先复习一下C语言当中的内存管理函数。
C语言当中内存管理:malloc/calloc/realloc/free
二,C++当中的内存管理方式
1,new和delete的使用
虽然C语言当中动态开辟内存的方式在C++当中依然可以进行使用,但是C++开创了自己内存管理的方式,即:通过new和delete操作符进行动态内存管理
内置类型的动态内存开辟:
自定义类型的内存开辟:
总结:在申请空间时,new会调用构造函数 ,delete会调用析构函数,但是malloc和free不会
除此之外,malloc会进行判空防止开辟失败,new开辟空间失败,会抛出异常。
展示:
32位下:
由此可见32位下在堆上申请1.8G左右的内存,而栈上一般申请8MB左右的内存
2,new和delete的底层实现原理
要想了解new和delete的底层原理,就要先知道operator new和operator delete函数
首先new和delete是用户开辟空间和释放空间的操作符,operator new和operator delete是系统提供的底层函数,new在底层调用operator new,delete在底层调用operator delete全局函数来释放空间。
operator new 的底层还是malloc,如果申请成功就返回,如果申请失败就抛出异常
operator delete的底层还是free来释放空间
自定义类型:
new的原理:
1,调用operator new函数申请空间
2,在申请的空间上使用构造函数,进行初始化
delete的原理:
1,调用析构函数,清理对象当中开辟的资源和空间。
2,调用operator delete函数释放对象中的空间。
注意:自定义类型new/free,malloc/delete不能进行混用,可能会出现内存泄漏等问题。
总结:不要错配使用,new/delete搭配,malloc/calloc/realloc/free搭配
3,定位new表达式
在某些时候我们将new的两个组成部分进行拆分使用,就要用到new表达式
new表达式:在已经分配的内存空间中调用构造函数并初始化一个对象 。
使用形式:new(对象名)对象类型(向构造函数传入的值)
展示:
class A { public: A(int a = 0) :_a(a) { cout << "A():" << this << endl; } ~A() { cout << "~A:" << this << endl; } private: int _a; }; int main() { A* p1 = new A(1); delete p1; //进行拆分--调用operator new相当于malloc A* p2 = (A*)operator new(sizeof(A)); //定位new表达式--在已经分配内存的空间中调用构造函数并初始化为2 new(p2)A(2); //可以直接通过指针调用析构函数 p2->~A(); operator delete(p2); return 0; }定位new表达式的使用场景比较少,一般是配合内存池进行使用,了解一下即可。
三,总结 :malloc/free和new/delete之间的区别
共同点:malloc/free和new/delete的共同点就是都需要从堆申请空间,并且需要手动释放空间。
不同点:
| 对比项 | malloc/free | new/delete |
|---|---|---|
| 语言 | C/C++ | C++ |
| 类型 | 函数 | 运算符 |
| 调用构造/析构 | ❌ 不调用 | ✅ 调用 |
| 返回值类型 | void*(需强转) | 类型安全不需要进行强转 |
| 失败处理 | 返回NULL(手动判空) | 抛异常(自动抛出) |
| 内存大小 | 手动计算 | 自动计算 |
| 数组支持 | 无特殊支持 | new[]/delete[](直接通过个数开辟) |
| 可重载 | 否 | 是 |
| 分配失败可扩容 | 可通过realloc调整 | 无直接对应(需自己实现) |
malloc/free是标准库函数,标准库函数不能够进行重载,但是new/delete是操作符,操作符可以进行重载。
