1、C语言中使用malloc/calloc/realloc/free进行动态内存管理,malloc/calloc/realloc用来在堆上开辟空间,free将申请的空间释放掉。 1)malloc 原型:void * malloc(size_t size); 该函数将在堆上分配一个size byte大小的内存。它分配的单原完全按字节大小计算,因此如此分配N个单原的student_t,那么要这样实现:(stdent_t )malloc(N sizeof (student_t)); (可用memset初始化) 2)calloc 原型:void* calloc(size_t size, int count); 该函数解决了上面的函数的不足,它将分配count个size大小的单原,因此在便用此函数的时候就会很方便,比如对上面的例子就可以:(student_t *)calloc(sizeof(t_student), N)就可以了。这样使用就会很清晰的知道分配的内存是一种什么样的逻辑方式。(会将申请的内存空间初始化) 3)realloc 改变原有内存空间的大小,若不能改变,则会开辟一段新的内存,将原有内存的内容拷贝过去,不会对新开辟的空间进行初始化。 4)_alloc 使用_alloc在栈上动态开辟内存,栈上空间具有函数作用域,在函数结束后系统自动回收,不用用户管理。
注意:堆上的内存需要用户自己管理,也就是说用户动态malloc/calloc/realloc的空间,必须自己free掉,否则会造成内存泄漏。 2、常见的内存泄漏
void MemoryLeaks(){ //1.内存申了忘记释放 int *pTest = (int *)malloc(10*sizeof(int)); assert(NULL != pTest); Do(); //2.程序逻辑不清,以为释放了,实际内存泄漏 int *pTest1 = (int *)malloc(10*sizeof(int)); int *pTest2 = (int *)malloc(10*sizeof(int)); Do(); pTest1 = pTesr2; free(pTest1); free(pTest2); //3.程序误操作,将堆破坏 char *pTest3 = (char *)malloc(5); strcpy(pTest3,"Memory Leaks!"); free(pTest3); //4.释放是传入的地址和申请时的地方不同 int *pTest4 = (int *)malloc(10*sizeof(int)); assert(NULL != pTest4); pTest4[0] = 0; pTest4++; Do(); free(pTest4);}1、C++中使用new和delete运算符进行动态内存管理。 【new作用】 调用Operator new分配空间。 调用构造函数初始化对象。 【delete作用】 调用析构函数清理对象 调用operator delete释放空间 【new[]作用】 调用operator new分配空间。 调用N次构造函数分别初始化每个对象。 【delete[]作用】 调用N次析构函数清理对象。(N是new[ ]出来的) 调用operator delete释放空间
2、C++的其他内存管理接口(placement版本) void * operator new (size_t size); void operator delete (size_t size); void * operator new [](size_t size); void operator delete[] (size_t size); 1) operator new/operator delete operator new[]/operator delete[] 和 malloc/free用法一 样。 2)他们只负责分配空间/释放空间,不会调用对象构造函数/析构函数来初始化/清理对象。 3)实际operator new和operator delete只是malloc和free的一层封装。
void Test() { int *p1 = new int; //动态分配4个字节(1个int)的空间单个数据 int *p2 = new int(2); //动态分配4个字节(1个int)的空间并初始化为2 int *p3 = new int[2]; //动态分配8个字节(2个int)的空间 delete p1; delete p2; delete[] p3; }
注意:new和delete、new[ ]和delete[ ]要匹配使用,否则会造成内存泄漏甚至崩溃的问题。 栈: 非静态局部变量/函数参数/返回值等等,栈是向下增长的。 数据段: 存储全局数据和静态数据(包括局部静态变量) 堆: 程序运行时的动态内存分配,可以向上增长的。 代码段: 可执行的代码和只读常量。 3、malloc/free和new/delete的区别和联系 1)都是动态内存管理的入口。 2)malloc/free是C/C++的标准库函数,而new/delete是C++的操作符 3)malloc/free只是动态的分配内存空间/释放空间。而new/delete除了分配空间还会调用构造函数和析构函数 4)malloc/free需要手动计算类型大小且返回值为void*,new/delete可以自己计算类型的大小,返回对应类型的指针。
class Array { public: Array(size_t size = 10) :_size(size) , _a(0) { cout << "Array(size_t size)" << endl; if (size > 0) { _a = new int[size]; } } ~Array() { cout << "~Array()" << endl; if (_a) { delete[]_a; _a = 0; _size = 0; } } PRivate: int* _a; size_t _size; }; void Test() { //malloc/free函数只是动态的分配内存空间/释放空间。 Array* p1 = (Array*)malloc(sizeof(Array)); //new/delete操作符除了分配空间还会调用构造函数和析构函数来初始化和清理。 Array* p2 = new Array; //1个类类型 Array* p3 = new Array(20); //1个类类型并初始化为20 Array* p4 = new Array[10]; //10个类类型 free(p1); delete p2; delete p3; delete[] p4; } int main() { Test(); //程序结果构造函数和析构函数被调用12次。 return 0; }4、定位new表达式 定位new表达式是在以分配的原始空间中调用构造函数初始化一个对象。 new(place_address) type; new(place_address) type(initializer-list); place_address必须是一个指针,initializer-list是初始化列表。 eg: 利用mallco/free和定位new表达式来模拟new/delete和new[]/delete[]:
class A { public: A(int a = 2) :_a(a) { cout << "A()" << endl; } void Print() { cout << _a << endl; } ~A() { cout << "~A()" << endl; } private: int _a; }; int main() { //分配1个A类型空间 A* pa = (A*)malloc(sizeof(A)); new(pa)A(1); //调用构造函数 pa->~A(); //调用析构函数 free(pa); cout << endl; //分配5个A类型的空间 A* pa1 = (A*)malloc(5 * sizeof(A)); for (int i = 0; i < 5; i++) { new(pa1 + i)A(i); //调用5次构造函数 } for (int i = 0; i < 5; i++) { (pa1+i)->~A(); //调用5次析构函数 } free(pa1); return 0; }结果如下:
新闻热点
疑难解答
图片精选