🎁个人主页:我们的五年
🔍系列专栏:C++课程学习
🎉欢迎大家点赞👍评论📝收藏⭐文章
目录
🎡1.new,delete和malloc,free的区别:
⌚️相同点:
⌚️不同点:
🎡2.new和free的实现原理:
1.对内置类型的处理:
2.对自定义类型的处理:
🎡3.为什么尽量要new和delete配套使用,malloc(calloc,realloc)和free配套使用?
🎡1.new,delete和malloc,free的区别:
⌚️相同点:
new,delete和malloc,free都是对动态内存进行管理的。动态内存是位于堆上的,不会随着函数生命周期的结束而结束,正因为这样,所以才要用户主动的进行空间释放。不然就会造成空间泄露。
●空间泄露:不是物理层面的消失,而是我们失去对某块空间的控制。
危害:长期运行的程序出现内存泄漏会使反应越来越慢,最终卡死。
⌚️不同点:
🏆1.new,delete是操作符,malloc,free是函数。
🥊操作符和函数的区别:
1.操作符在编译的过程就进行了替代,而函数要在运行中进行调用。
2.操作符不需要要有头文件,由编译器实习,而函数必须要有具体实现。
🏆2.是否能进行初始化:
malloc不可以进行初始化。new可以进行初始化,也可以不进行初始化。
🏆3.是否需要进行类型转化:
malloc申请的空间是void*,所以要进行类型转化,new申请的空间里面有类型,不需要进行转化。
🏆4.空间大小的计算:
malloc要明确申请空间的大小(单位:字节),但是new只要明确申请几个就可以了,申请多个时,在类型后面加[个数]。
🏆5.是否主动调用构造函数和析构函数:
在处理自定义类型的时候,new会调用构造函数,delete会主动调用析构函数对类里面的空间进行清理。但是malloc和free就不会调用。
🏆6.申请失败的返回值不同:
malloc申请失败的时候返回NULL指针,所以申请完以后,要进行判空。new需要捕获异常。
🎡2.new和free的实现原理:
1.对内置类型的处理:
从下面的例子也可以看出来,new可以对申请的空间进行初始化。malloc不能对申请的空间进行初始化,calloc虽然可以初始化,但是都是0,不能根据具体的实际情况进行初始化,所以也是不能初始化。
#include<iostream>
using namespace std;int main()
{//申请一个int空间int* p1 = new int(10);//malloc申请空间的大小,不进行初始化int* p2 = (int*)malloc(sizeof(int));//calloc进行初始化,每个字节都初始化为0int* p3 = (int*)calloc(1, sizeof(int));//对空间进行扩容,如果为空指针,功能相当于mallocint* p4 = (int*)realloc(nullptr, sizeof(int));//申请多个int空间,后面跟着初始化列表int* p5 = new int[5] {1, 2, 3};free(p2);delete p1;//释放多个空间的时候,用delete[] 指针delete[] p5;
}
2.对自定义类型的处理:
在自定义这个层面,new和malloc的区别就不止有new可以进行初始化,还有new会主动调用构造函数,delete会调用析构函数。
#include<iostream>
using namespace std;class A {
public:A() {cout << "A()" << endl;}~A() {cout << "~A()" << endl;}
private:int _a;
};
int main()
{A* p1 = new A;delete p1;cout << "aaa" << endl;A* p2 = (A*)malloc(sizeof(A));free(p2);cout << "aaa" << endl;return 0;
}
3.原理:
⌚️new的原理:
1.operator new函数申请空间
2.在申请的空间上调用构造函数。
⌚️delete的原理:
1.执行析构函数对对象中的资源进行清理。
2.调用operator delete对对象进行清理
new T[ ]和delete[ ]原理和上面类似。
operator new和operator delete是系统提供的全局函数,底层还是通过malloc和free进行实现的。
🎡3.为什么尽量要new和delete配套使用,malloc(calloc,realloc)和free配套使用?
因为我们如果下面这种情况下,如果是new申请的空间,用free进行释放空间,就会发生错误。
⌚️在类里面我们显式实现了析构函数的时候,用new申请多个类对象的时候,会多申请4个字节(一个int类型的大小)保存申请了多少个类。
#include<iostream>
using namespace std;class A {
public:~A() {cout << "~A()" << endl;}
private:int _a;
};
int main()
{A* p1 = new A[10];A* p2 = (A*)malloc(sizeof(A) * 10);return 0;
}
这时候申请的大小是:4*10+4=44字节
但是如果没有显式实现析构函数,就不要那多出来的四个字节来保存申请了多少个类。
但是new申请的空间返回的是多申请的那四个字节的后面那10个A空间起始位置。
如果我们直接用free释放这一位置,前面多申请的那四个就没有被释放,就发生内存泄漏。