文章目录
前言
在C语言中我们使用malloc、realloc、calloc来动态开辟内存空间,虽然在C++里面也能使用它们,但因为C++新增了需要C语言所没有的特性,使得C语言老的那套已经不再适合C++。
一、内存区域划分
在介绍C++的新机制前,我们先来了解一下C++内存的区域划分。
- 栈:用于存放局部变量,数据由高位向低位增长,数据的释放由编译器来控制。
- 内存映射段:高效的 I/O 映射方式,用于装载一个共享的动态内存库,创建共享内存,做进程间通信。
- 堆:用于存放动态开辟的内存,数据由低位地址向高位地址上升,开辟的空间需要手动释放。
- 数据段:用于存放已经初始化的全局变量和静态变量。
- 代码段:存放可执行的代码/只读常量。
二、new 与 delete
为了适应C++的类和异常机制
,C++新增了两个新的操作符,new 与 delete,它们和C语言开辟空间的方式类似,必须手动开辟,手动释放。
- new:用于动态开辟内存空间。
- delete:用于删除开辟的内存。
开辟内置数据类型
int main()
{
// 动态开辟一个int类型的空间
int* p1 = new int;
// 动态开辟一个int类型的空间并初始化为10
int* p2 = new int(5);
//动态开辟一个10个int类型的空间
int* p3 = new int[10];
// 必要自己手动释放空间
delete p1;
delete p2;
delete[] p3;
return 0;
}
注意:new和delete要配套使用,申请连续的空间时,必须使用带 [ ] 的 new 与 delete。
开辟自定义类型
new 在开辟类的空间时,必定会调用其构造函数, 而 delete 时会调用其析构函数,但C语言中的 malloc 与 free 函数并不会调用。
class A
{
public:
A(int a = 0) : _a(a) {cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
private:
int _a;
};
int main() {
A* aa = new aa[10];
A* a2 = (A*)malloc(sizeof(A) * 10);
delete [] aa;
free(a2);
}
结果可得知:A()被调用了10次,~A()被调用了10次
二、operator new 与operator delete函数
虽然new 与 delete它们是操作符,但在使用时还是调用了全局函数,现在让我们深入它们的内部,了解它们是如何工作的吧。
operator new
new 在使用时调用的全局函数operator new来动态开辟空间
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void *p;
// 使用malloc申请size字节空间
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{
// 如果申请失败抛出异常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
从这里我们可以看出来,其实new 不只是为了类服务的,同时还为了C++的异常服务。
operator delete
delete 也是一样调用了对应的operator delete 全局函数来释放空间。
void operator delete(void *pUserData)
{
_CrtMemBlockHeader * pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK); /* block other threads */
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg( pUserData, pHead->nBlockUse );
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
}
/*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
我们最终可以发现 new 与 delete 的内部设计也时用 malloc 与 free 来实现的
new 与 delete 的实现原理
在申请内置类型的时候,malloc/free 与 new/delete 之间没有太大区别,但 new/delete 在申请连续空间时需要使用 [ ] ,而且在开辟失败时会抛出异常。
new 的原理
- new 的原理
- 调用operator new函数申请空间
- 在申请的空间上执行
构造函数
,完成对象的构造
- new T[N] 的原理
- 调用operator new[]函数申请空间,完成N个对象空间的申请
- 在申请的空间上执行N次构造函数
delete 的原理
- delete 的原理
- 先执行
析构函数
,完成对象中资源的清理 - 调用operator delete函数释放空间
- 先执行
- delete[]的原理
- 在释放的对象空间上执行N次析构函数,完成N个对象资源的清理
- 调用operator delete[]来释放空间。
总结
性质 | 是否抛出异常 | 是否调用析构/构造 | |
---|---|---|---|
malloc | 函数 | 否 | 否 |
new | 操作符 | 是 | 是 |
free | 函数 | 否 | 否 |
delete | 操作符 | 是 | 是 |