一,C语言中动态内存管理
C语言中使用了malloc/calloc/realloc/free进行动态内存管理,malloc/calloc/realloc用来在堆上开辟空间,free用来释放申请的空间。
malloc的原型,作用:
calloc的原型,作用:
realloc的原型,作用:
二,C++中动态内存管理
我们知道在C++中,我们还是可以使用C库中的上面的三个函数来开辟内存的,但是有时会使用不方便,所以C++还为我们提供了新的开辟内存的方式。下面是C++开辟内存的个列:
class Array
{
public:
Array(size_t size = 5)
:_a(NULL)
, _size(size)
{
cout << "Array create" << endl;
_a = new int[size];
}
~Array()
{
if (_a != NULL)
{
delete[] _a;
_a = NULL;
cout << "Array destroy" << endl;
}
}
private:
int * _a;
size_t _size;
};
int main()
{
Array *p0 = NULL;
Array *tmp = (Array *)malloc(sizeof(Array));//需要判断是否开辟成功
if(tmp)
{
Array *p0 = tmp;
}
Array *p1 = new Array;
Array *p2 = new Array(10);
Array *p3 = new Array[5];
free(p0);
delete p1;
delete p2;
delete[] p3;
system("pause");
return 0;
}
运行结果如下:
从图中看出,指针p0指向的是使用malloc开辟的空间,这个过程并没有调用构造函数,且在使用malloc的时候,我们必须判断是不是开辟成功了。而p1指向的是使用new方法开辟的内存,这个过程,调用了构造函数,生成了对象,对于C++是面向对象语言来说,是非常的便捷的,且在使用new开辟的时候,我们比不需要繁琐的去判断内存是否开辟成功。p3指向是使用了new[ ] 开辟的内存,且一次开辟了5个对象的内存,都调用了构造函数。
在释放我们申请的内存时,malloc的内存申请,要用free释放,且并没有调用析构函数,而delete 和delete [ ] 释放内存时,都调用了析构函数,清理资源,然后再释放内存。
既然 new/delete , new[ ] / delete [ ] 在开辟内存时,比malloc使用起来那么的便捷,我们看看它底层是怎么实现的:
当我们运行到new时,按F11进去看看new是什么:
由于在构造函数中,我们使用的是new [ ],可以看到new [ ] 的底层也是调用new:
再看看new:
可以看到new的底层也是调用malloc来开辟空间的,但是new的里面还有一个机制,那就是判断是否开辟成功的判断,如果系统空间不足,会抛出异常,这时就需要程序员手动的去释放我们不使用被占用的内存块,我们释放了些内存后,它会继续的申请。这就使我们在使用new /new[ ]时,不需要去判断是否申请空间成功了。
同样的我们看看delete/delete[ ] 是怎么样实现的:
我们可以看到delete[ ]的里层也是调用了delete,而delete的里层调用的是free_dbg,那么free_dbg是什么的,我们再看看free是定义是什么:
free里层也是调用了free_dbg,其实delete / delete[ ] 也是调用了free。
new/delete 大概的过程如下:
new[ ] / delete [ ] 是怎么的过程呢?
上面的列子可以看出,new[ ] / delete [ ] 是对new/ delete的调用,那么传的参数有什么要求?
class A
{
public:
A()
:a(0)
{
cout << "调用构造函数!" << endl;
}
~A()
{
cout << "调用析构函数!" << endl;
}
private:
int a;
};
int main()
{
A *p = new A[20];
delete[] p;
return 0;
}
从代码可以看到,我们new了20个对象,每个对象的大小是4个字节,系统应该是开辟了20*4=80个字节。但是我们看看new[]调用new时,传的参数为多少。
传的是84,多了4个字节,那么系统为什么多申请了4个字节呢。
注意:
new操作符、操作符new、定位new表达式的区别:
1.new操作符
new,delete操作符是C++用来动态内存申请的关键字
2.操作符new
操作符new是一个函数:如上面的new的底层,调用的是operator new(size_t size)函数。
void* operator new(size_t size);
void operator delete(size_t size);
void* operator new[](size_t size);
void operator delete[](size_t size);
是函数。与其他的operator重载函数不同。operator new 和 operator delete 只是malloc和free的一层封装
3.定位new表达式
定位new表达式是在已经分配的原始内存空间中调用构造函数初始化一个对象。
new(place_address)type
new(place_address) type(initializer_list)
place_address 必须是一个指针
initializer_list 是类型的初始化列表