特征 | new/delete | malloc/free |
---|---|---|
分配内存的位置 | 自由存储区 | 堆 |
返回类型安全性 | 完整类型指针 | void* |
内存分配失败返回值 | 默认抛出异常 | 返回NULL |
分配内存的大小 | 由编译器根据类型计算得出 | 必须显式指定字节数 |
处理数组 | 有处理数组的new版本new[] | 需要用户计算数组的大小后进行内存分配 |
已分配内存的扩充 | 无法直观地处理 | 使用realloc简单完成 |
是否相互调用 | 可以,看具体的operator new/delete实现 | 不可调用new |
分配内存时内存不足 | 无法通过用户代码进行处理 | 能够使用realloc函数或重新制定分配器 |
函数重载 | 允许 | 不允许 |
构造函数与析构函数 | 调用 | 不调用 |
内存分布:
栈向下增长,堆向上增长。
1、栈区(stack):编译器自动释放,存放为函数运行的局部变量、函数参数、返回数据、返回地址,操作方式类似于数据结构中的栈(push,pop)。
2、堆区(heap):程序员分配释放,若不释放,程序结束时由OS回收,分配方式类似于链表。
3、静态区(全局区/static):存放全局变量、静态数据、常量。程序结束由系统释放。
4、文字常量区:常量字符串。程序结束由系统释放。
5、程序代码区:存放函数体(类成员函数和全局函数)的二进制代码。
1、malloc、calloc、relloc、free
malloc()从堆里获取空间,malloc函数返回的指针指向堆里的一块内存。操作系统里有一个记录空闲内存地址的链表,当操作系统收到程序申请时会遍历链表。
2、new、delete
new返回分配单元的起始地址,返回值保存在一个指针变量,若分配不成功,返回null,并抛出异常。
new没有为创建的对象命名,只能通过指针去访问对象或数组。
delete释放内存,只是销毁内存上的对象,但指针仍存在,仍然只想原来内存,保存原来空间的地址,所以应在释放之后将指针置空,以免之后引用造成问题。
3、delete、delete[ ]
delete回收new开辟的单个对象指针指向的内存
delete[ ]回收new[ ]开辟的对象数组指针指向的内存
delete只会调用一次析构函数
delete [ ]会调用每一个成员的析构函数(当delete操作符用于数组时,它为每个数组元素调用析构函数,然后调用operator delete来释放内存)
new[ ]开辟数组空间要多出4个字节存放数组大小
delete[ ]要与new[ ]配套使用
4、为什么还要用new/delete
new运算符不需要强制类型转换,使用简单;
new通过调用构造函数初始化创建对象,执行效率高;
new能够进行异常处理,使用安全;
对于非内部数据类型的对象而言,malloc、free不能满足动态对象的要求,new调用构造函数,delete调用对象的析构函数,而malloc/free是库函数,不在编译器控制范围内,不能执行构造函数、析构函数的任务;
new建立的是一个对象,malloc分配的是一块内存
5、注意问题
如果在函数上定义一个指针变量,然后在这个函数里申请了一块动态分配的内存让该指针指向它,实际上,指针的地址在栈上(函数定义的变量在栈),但指向的内从容在堆上,所以,函数返回时,函数所在的栈被销毁,指针被销毁,但是申请的内存没有销毁,只有程序员结束释放所有内存才会释放它们,与函数是否结束无关,所以在函数退出之前释放内存,并给指针置空。
void Function(void)
{
char *p = (char *)malloc(100 * sizeof(char));
}
原文链接:https://blog.csdn.net/qq_40840459/article/details/81268252