C++内存管理方式
接C++内存管理(一)来继续阐述
new/delete操作内置类型
int main()
{
int* ptr1 = new int;//动态申请一个int大小的空间
int* ptr2 = new int(5);
//将ptr2指针所指向的空间中的值初始化为5
int* ptr3 = new int[4];//动态申请连续的4个int大小的空间
ptr3[1] = 1;//可以正常使用进行解引用等
ptr3[2] = 2;
//当然也要进行释放
delete ptr1;
delete ptr2;
delete[] ptr3; //连续的空间需要加上[]进行释放
return 0;
}
- 指针ptr1在堆上申请了一个int大小的空间
- 指针ptr2在堆上申请了一个int大小的空间,并且将空间中的值置为5
- 指针ptr3在堆上申请了连续的4个int大小的空间,并且用ptr3指向该空间头部
- delete 进行空间的释放,ptr1、ptr2直接进行释放即可,但是,ptr3由于是连续多个int空间,所以释放时候需要使用delete[]来进行释放
注意:new/delete是两个操作符,不同于C语言中的malloc/free,malloc/free为函数,而new/delete为操作符
new/delete操作自定义类型
动态申请单个自定义类型空间
首先,定义一个自定义类型Test类
class Test
{
public:
Test()
:data(10)
{
cout << "Test()" << this << endl;
}
Test(int _data)
:data(10)
{
cout << "Test()" << this << endl;
}
~Test()
{
cout << "~Test()" << this << endl;
}
private:
int data;
};
//进行new与delete的测试
int main()
{
Test* iptr1 = new Test; //调用默认的构造函数,如果用户显式给出,则没有默认构造,则会出错
Test* iptr2 = new Test(10); //调用带有参数的构造函数
delete iptr1, iptr2;
return 0;
}
- 如果类中没有给出构造函数, 则new时只能使用第一种方式,new Test后不带有括号括号是传递参数的,默认的构造函数是无参的
- 如果类中显式定义了构造函数,则类中将不存在默认的构造函数,所以,new在调用时,只能调用类中给出的构造函数的参数类型。必须使用new Test(参数)进行new申请
动态申请连续的自定义类型空间
int main()
{
Test* ptr = new Test[10];
delete[] ptr;
return 0;
}
- 申请连续的自定义类型空间new Test[10],用delete[] ptr来进行回收。申请了十个空间,所以调用构造函数10次,释放10个空间所以调用析构函数10次
operator new与operator delete函数
库文件中的operator new 与 operator delete**
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,尝试执行空间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
operator delete:该函数最终是通过free来释放空间的。、
👇下面是operator new 与operator delete 的源码:可供参考
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);
}
/* operator delete: 该函数最终是通过free来释放空间的 */
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;
}
- 通过上述的源码我们可以了解到, new 与 delete 底层都是使用的malloc与free来进行申请与释放空间的,并且对于空间的把控更为严谨加入了抛出 / 捕获异常机制
- 如果C语言中,malloc申请空间失败,则会返回一个NULL指针
operator new[ ] 源码
// newaop -- operator new[](size_t) REPLACEABLE
#include <new>
void *__CRTDECL operator new[](size_t count) _THROW1(std::bad_alloc)
{ // try to allocate count bytes for an array
return (operator new(count));
}
/*
* Copyright (c) 1992-2007 by P.J. Plauger. ALL RIGHTS RESERVED.
* Consult your license regarding permissions and restrictions.
V5.03:0009 */
我们可以看出,operator new[ ]在底层调用的是operator new来进行申请空间的。
new/delete实现原理
对于内置类型
对于内置类型,C++可以知道该内置类型的大小,所以,new 会调用operator new(operator new 会调用 malloc)来进行申请内置类型大小的空间。
delete 也会相应的直接调用free来释放对应的空间。
对于自定义类型
new / delete
对于自定义类型的空间申请,由于new不清楚内置类型空间的大小, 所以在使用new申请空间时,需要先对于自定义类型的构造,然后再在堆上申请相应的空间大小。
delete 先在相应对象上执行析构函数,然后再完成对象的资源清理。
new[ ] / delete[ ]
申请自定义类型的连续空间,需要没申请一块空间,都需要调用构造函数进行申请,释放时,也需要没释放一次空间,都需要调用析构函数。👇