
C中的动态内存管理
malloc

int* pi = (int*)malloc(sizeof(int) * 10);
calloc

并初始化为 0 值
int* pi = (int*)calloc(10, sizeof(int));
realloc

int* new_pi = (int*)realloc(pi, sizeof(int)*100);
free

realloc 申请的空间
free(new_pi);
小结
C中的动态内存管理方式,不能很好地支持自定义类型,所以 C++ 中有了 new 和 delete
A* a = (A*)malloc(sizeof(A)); // 为 A 类型申请空间,但不能初始化
C++中的动态内存管理
new & delete
int* pi = new int; // 申请 1 个 int 类型的空间
int* pi1 = new int(0); // 初始化为 0
int* pi2 = new int[10]; // 申请 10 个 int 类型的空间
A* pa = new A; // 申请 1 个 A 类型的空间,并调用默认构造初始化
delete pi;
delete pi1;
delete[] pi2;
delete pa; // 调用 A 类的析构函数,并释放空间
使用 new 动态申请的内存,必须使用 delete 释放
与 C 中对动态内存管理方式的区别:
对于自定义类型,new 会开空间 + 调用构造函数初始化,delete 会调用析构函数 + 释放空间。
但是对内置类型,处理基本一样,开空间但不会初始化。
另外,new 在申请空间失败后会抛出异常,需用 try catch 捕获;malloc 申请失败后,会返回 NULL
new[ ] & delete[ ]
A* pa = new A[10];
delete[] pa;
new A[n] 和 delete[ ] pa 是对多个对象空间的申请和释放操作,其中,分别调用了 operator new[ ] 与 operator delete[ ] 函数;过程与单个对象空间的申请与释放,基本没有区别。
但是为多个对象开辟和释放空间时,一般 new 会额外开辟空间存取开辟的对象个数(不同编译器的实现方式可能不同),以便 delete 时,编译器知道该释放掉多大空间。
operator new
针对自定义类型,使用 new 创建对象,实际上做了两步操作:
(1)调用了底层的 operator new 这个全局函数申请空间
(2)调用该自定义类型的构造函数
如下图(vs中 new 对象,调试时的汇编指令),在整个 new 对象的过程中, call 了两个函数:operator new 和 A 类的默认构造:
借鉴一下C友的源码:
void* __CRTDECL operator new(size_t const size)
{
for (;;)
{
if (void* const block = malloc(size)) // 调用了 malloc
{
return block;
}
if (_callnewh(size) == 0)
{
if (size == SIZE_MAX)
{
__scrt_throw_std_bad_array_new_length();
}
else
{
__scrt_throw_std_bad_alloc();
}
}
// The new handler was successful; try to allocate again...
}
}
发现 operator new 函数中,实际调用了 malloc 来申请内存
operator delete
同理,针对自定义类型,C++ 中的 delete 也是分两步走:
(1)调用该类型的析构函数
(2)调用 operator delete 释放申请的空间
void __CRTDECL operator delete(void* const block) noexcept
{
#ifdef _DEBUG
_free_dbg(block, _UNKNOWN_BLOCK);
#else
free(block);
#endif
}
operator delete 的源码中,仍然是调用了 free 来释放内存。
operator new[ ] & operator delete[ ]
同单个对象的空间申请与释放步骤一样,多个对象 new A[ ] 和 delete[ ] p 时:
new A[ ] :调用多次operator new[ ] + 构造函数
delete [ ] p :调用多次析构函数 + operator delete[ ]
小结
new 和 delete、malloc 和 free 匹配使用,否则行为将未定义。
new 和 delete、malloc 和 free 共同点:都是从堆上申请空间,并且需要手动释放。
区别:
1、malloc 和 free 时函数,new 和 delete 是操作符;
2、malloc 申请的空间不会初始化,而 new 可以初始化;
3、malloc 申请空间时,需要手动计算大小并传参;而 new 只需要在后面跟上类型以及对象个数;
4、malloc 的返回值为 void* ,需要强制转换指针;而 new 因为后跟类型的原因,不需要转换指针类型;
5、malloc 申请失败返回 NULL,对 malloc 使用必须加判空语句;而 new 需要捕获异常;
6、针对自定义类型,malloc/free 只能开辟空间,不会调用构造函数和析构函数;而 new/delete 会在申请空间时调用构造函数完成对象的初始化,delete 会在释放空间之前调用析构函数完成空间中的资源清理。
思考:new 和 delete 目的就是在面向对象编程中,支持自定义类型对象的空间申请、初始化以及资源释放。