对于32位的机器,内存空间大小为4GB,从低地址到高地址,分别划分区域为:正文代码、初始化数据、未初始化数据、堆、共享区、栈区与命令行参数环境变量几个部分。其中需要注意的是栈的地址是从高地址向低地址使用的,而堆区相反。
可以参考过往博客:【C/C++】基础:动态内存管理-CSDN博客,其中详细介绍了C语言关于动态内存开辟的由来与优势,再介绍动态内存开辟的方法,最后会列举常见错误与相应练习帮助大家巩固。
作用:由于C语言无法用原存在的关于动态内存管理的方法,来对自定义类型进行构造函数的调用,因而引入new
和delete
使用
内置类型:包括初始化和不初始化两种形式
int *p1 = new int;// 不初始化
int* p2 = new int(0);//初始化
自定义类型:包括初始化和不初始化两种形式
A* pa1 = new A;
A* pa2 = new A(2);
数组:内置类型包括初始化和不初始化两种形式,自定义类型无法初始化
int* p3 = new int[10];// 不初始化
int* p4 = new int[10]{1,2,3,4,5,6};//初始化
A* pa3 = new A[10];
注意:
作用:封装C语言的动态内存管理,将返回空指针更改为抛出异常,符合C++的设计要求
operator new
:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,尝试执行空间不足应对措施,如果更改应对措施用户设置,则继续申请,否则抛异常。operator delete
: 该函数最终是通过free来释放空间的,释放空间失败抛异常源码:
void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void* p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{
// report no memory
// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
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;
}
说明:
与malloc
和free
的区别:operator new
实际通过malloc
来申请空间,当malloc
申请空间成功时直接返回;申请空间
失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
对于自定义类型而言,内置类型相似:
与new
的关系: 为调用了operator new
,调用封装malloc
,再调用构造函数
从汇编角度理解:
int *p1 = new int;// 不初始化
......
009B1C99 call operator new (09B114Ah)
......
与new[]
的关系如果是是数组则会调用new[]
,原理为:调用operator new[]
后,调用operator new
,最后调用封装malloc
,以及调用多次构造函数
从汇编角度理解:
int* p3 = new int[10];// 不初始化
......
009B1CF8 call operator new[] (09B11E0h)
......
与delete
的关系:调用析构函数 再调用operator delete
释放空间
从汇编角度理解:
delete p1;
......
001A1CFF call operator delete (01A10AAh)
......
与delete[]
的关系:调用多次析构函数,再调用operator delete[]
,在调用operator delete
释放空间
从汇编角度理解:
......
001A1D3C call operator delete[] (01A1320h)
......
作用:对已有的空间初始化
使用:new (place_address) type
或者new (place_address) type(initializer-list)
,其中place_address
必须是一个指针,initializer-list
是类型的初始化列表
定位new
A* p1 = (A*)malloc(sizeof(A));
if (p1 == nullptr){
perror("malloc fail");
}
new(p1)A(1);
A* p1 = (A*)malloc(sizeof(A));
if (p1 == nullptr){
perror("malloc fail");
}
new(p1)A;
显示调用析构函数
p1->~A();
free(p1);
常见场景:定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。
malloc
和free
是函数,new
和delete
是操作符malloc
申请的空间不会初始化,new
可以初始化 malloc
申请空间时,需要手动计算空间大小并传递,new
只需在其后跟上空间的类型即可,如果是多个对象,[]
中指定对象个数即可malloc
的返回值为void*
, 在使用时必须强转,new
不需要,因为new
后跟的是空间的类型malloc
申请空间失败时,返回的是NULL
,因此使用时必须判空,new
不需要,但是new
需要捕获异常malloc/free
只会开辟空间,不会调用构造函数与析构函数,而new
在申请空间后会调用构造函数完成对象的初始化,delete
在释放空间前会调用析构函数完成空间中资源的清理malloc
申请空间失败时,返回的是NULL
,因此使用时必须判空,new
不需要,但是new
需要捕获异常malloc/free
只会开辟空间,不会调用构造函数与析构函数,而new
在申请空间后会调用构造函数完成对象的初始化,delete
在释放空间前会调用析构函数完成空间中资源的清理不同编译器存在不同区别,常见如下:对于new T[]
,编译器会在开辟数组空间前,提前开辟一个整型空间,用于存放数组个数,由此,在调用delete[]
时,就会通过该整型数组获取数组大小,从而得知调用调用析构函数的次数。而delete则不需要多开辟一个整型空间