堆内存管理的区别
C语言的内存管理:
1、C语言中没有堆内存管理的语句,而是在C标准库中提供了一套堆内存管理的函数,在使用时还需要包含stdlib.h头文件。
2、malloc系列函数申请堆内存时需要提供字节数,可能会出现字节数不够或过多的情况。
3、malloc系列函数返回的是void类型的地址,如果想在C++中继续使用malloc系列函数,则必须对返回值进行强制类型转换,原因就是在C++中void类型的地址不能再自动转换成其它类型的地址。
4、malloc系列函数不能对申请到的内存设置初值,只有calloc函数可以把申请到的内存初始化0,或者之后调用memset、bzero函数进行初始化。
5、在C++中malloc系列函数为结构、联合、类对象申请、释放内存时,不会自动调用构造、析构函数。
6、在申请数组型的内存块时,可以使用malloc或calloc,释放时也使用free函数。
7、malloc系列函数申请内存失败时会返回NULL地址。
C++的堆内存管理:
1、C++中有堆内存管理的语句,可以new、delete运算符管理堆内存,直接使用不需要包含任何头文件。
2、new运算符在申请内存时只需要提供数据类型,它会自动计算所需要的字节数,每次申请的字节数都刚刚好,不多不少。
3、new运算符返回的是带类型的地址,申请时提供是什么类型,返回的地址就是什么类型的。
4、new在申请内存时,还可以对申请到的内存设置初值。
5、new/delete为结构、联合、类对象申请、释放内存时,会自动调用构造、析构函数。
6、在申请数组型的内存块时,使用new 类型[n],释放内存时使用delete[],不能与new/delete不能混用,因为new[]/delete[]会自动调用n次构造、析构函数,而new/delete只调用一次构造、析构函数。
7、当使用new申请内存失败时,会抛出std::bad_alloc异常,而不是返回空地址。
#include <iostream> #include <stdlib.h> using namespace std; struct Student { int id; char name[20]; short age; float score; Student(void) { cout << "构造函数" << endl; } ~Student(void) { cout << "析构函数" << endl; } }; int main(int argc,const char* argv[]) { int* p = new int(123456); cout << *p << endl; delete p; /* Student* stup = new Student; delete stup; */ /* Student* stup = (Student*)malloc(sizeof(Student)); free(stup); */ /* Student* stus = new Student[~0]; delete[] stus; */ return 0; }
new/delete和malloc/free的相同点:
1、都可以管理堆内存。
2、返回的都是地址,只是类型不同。
3、都必须配合指针变量使用。
4、delete和free都可以释放空指针,但都不能重复释放。
常考面试、笔试题:new/delete和malloc/free的相同点和不同点?
问题:delete[] 释放内存时为什么可以调用n次析构函数。
使用new[] 申请数组型的堆内存时(结构、联合、类对象),所申请内存块的前4个字节,记录着内存块的块数,所以使用delete []释放内存时可以准确调用n次析构函数。
Student* stus = new Student[13]; cout << *((int*)stus-1) << endl; delete[] stus;
问题:在C++中如何把已有一块内存(从操作系统获取到的内存,例如:ipc共享内存)分配给结构、联合、类对象,能自动调用构造、析构函数。
// new(内存地址) 类型; new运算符可以重新解释一块内存,并自动调用构造函数 int main(int argc,const char* argv[]) { void* ptr = malloc(sizeof(Student)); cout << ptr << endl; Student* stup = new(ptr) Student; cout << stup << endl; delete stup; return 0; }