C/C++ 动态内存管理
C语言:
在C语言中,有三个在堆上开辟内存的函数,它们分别是
@ (C语言) [malloc,realloc,calloc]
malloc
void* malloc(size_t size); * 它返回一个void*类型的指针,在堆上开辟一个大小为size字节的一段连续空间。
realloc
void* realloc (void* ptr, size_t size);
指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)。
新的大小可大可小(如果新的大小大于原内存大小,则新分配部分不会被初始化;如果新的大小小于原内存大小,可能会导致数据丢失。
calloc
在内存的动态存储区(堆)中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;并且把数据初始化为0。如果分配不成功返回NULL。
这三个函数都对应的是free( )
注意::
1:动态开辟的内存,要释放,不然会造成内存泄漏,什么是内存泄漏呢?大家可以看这篇博客
[http://blog.csdn.net/invisible_sky/article/details/78205461?locationNum=6&fps=1]
2::free(NULL)程序会崩溃;也就是说,如果free(a)。a这个指针没有指向一块动态开辟的空间,那么程序就会崩溃。
3::对一块空间free()多次,程序也会崩溃。
4::free()一块完整空间的一部分,也是不允许的,程序也会崩溃。
C++:
C++也有三个在堆上申请内存的函数:
(1):new + 类型名
例如:int * p = new int ;
(2):new + 类型名+(初始化的数)
例如:int * p = new int (0);
开辟一个大小为4个字节(int)的空间,用p来维护,并且把这段空间初始化为0;
(3):new + 类型名 + [个数]
例如:int * p = new int [10];
开辟一个大小为sizeof(int)*(10)个字节的空间,可以理解为开辟了一个类似于数组的连续空间,长度为10;
总结:
new与malloc,calloc,realloc的不同:
(1):new不需要手动计算类型大小,而其他三个需要
(2):new不需要返回的强制类型转换(默认为new后面紧跟的类型名),而其他三个则需要强制类型转换,不然编译器会报错
(3):new与delete匹配使用,其他三个与free匹配使用
(4):最重要的一点,new 一个类,它会自动调用这个类的构造函数,然后delete的时候会调用这个类的析构函数;
delete 用于释放new分配的内存,和new成对调用
free用于释放malloc分配的内存,和malloc成对调用
使用free释放时需要判断指针是否为NULL,delete不用
free释放内存,但不调用对象的析构函数
delete不仅释放内存,还调用对象的析构函数
delete和new是对对象的操作,是运算符
free和malloc是对内存空间的操作
例如:
#include <iostream>
using namespace std;
class AA
{
public:
AA(int a = 0)
:_a(new int (a))
{}
~AA()
{
delete _a;
}
private:
int *_a;
};
int main()
{
AA* p = new AA[4];//new了AA类的四个对象
delete[] p;
return 0;
}
AA* p = new AA[4];
这句可以理解p指向一个空间(这个空间是4个AA类的对象组成的连续空间)也可以理解成对象数组;但是这个空间在堆上;
要知道它会调4次拷贝构造和4次析构函数;试想编译器怎么知道需要调几次;所以请看下面:
相同点:
(1): 本质上new还是用malloc实现的;为什么这么说呢,当然是用依据的,请看下图:
new[] 去调operator new[]
operator new[] 去调operator new
operator new 去调 malloc
free一段new [] 开辟的空间,程序会崩溃
delete[] 在释放内存之前需要把指针往前移,让指针指向空间的起始位置;了解了这一点,我们就可以用free暂时替代delete的作用:
接下来,我们实现NEW_ARRAY/DELETE_ARRAY宏,模拟new[]/delete[]申请和释放数组:
要这么做,首先要清楚的了解new/delete和new[]/delete[]到底做了哪些事情?
(1):new做了两件事情:调用operator new分配空间;调用构造函数初始化对象。
(2):delete也做了两件事情:调用析构函数清理对象;调用operator delete释放空间。
(3):new[N]:调用operator new分配空间;调用N次构造函数分别初始化每个对象。
(4): delete[]:调用N次析构函数清理对象;调用operator delete释放空间。
代码实现如下::
#include <iostream>
using namespace std;
#define NEW_ARRAY(PTR,TYPE,N) \
do \
{ \
PTR = (TYPE*)malloc(sizeof(TYPE)*N+4);//多开4个字节的空间,用来存放需要调用拷贝构造和析构的次数 \
*(int*)PTR = N; \
PTR= (TYPE*)((int*)PTR+1); \
for (size_t i = 0; i < N; i++) \
new(PTR + i)TYPE; //调拷贝构造 \
} while (0);
#define DELETE_ARRAY(PTR,TYPE) \
do \
{ \
size_t N = *((int*)PTR - 1); \
for (size_t i = 0; i < N; i++) \
PTR[i].~TYPE(); //调析构函数 \
PTR = (TYPE*)((int*)PTR-1);//把指针向前移动4个字节,指向空间的起始位置 \
free(PTR); \
} while (0);
class AA
{
public:
AA(int a = 0)
:_a(new int (a))
{}
~AA()
{
delete _a;
}
private:
int *_a;
};
int main()
{
AA* p = NULL;
NEW_ARRAY(p,AA,4);
DELETE_ARRAY(p,AA);
return 0;
}