1.前言
在C语言中,有四个内存管理函数:malloc,calloc,realloc和free
但是使用起来他们却是非常的不方便:
int *p1=(int*)malloc(sizeof(int)*n);
int* p2 = (int*)calloc(4, sizeof (int));
int* p3 = (int*)realloc(p2, sizeof(int)*10);
同时这里也会出现一个问题,malloc不会进行初始化变量,并且这个p1对象也不会被自动的调用析构函数来释放不需要利用的空间。
因此c++为了解决上述这个问题:c++自己搞了一个内存管理的关键字,这就引出了new和delete的概念
即用new来初始化一个对象,并且在出了作用域之后会自动的调用析构函数
2.new
2.1 new的使用方法
1. 开辟连续的多个空间
int* p = new int[100];
代码的理解如下:
2.开辟一个空间并初始化
class A
{
public:
A(int a = 0)
: _a(a)
{}
private:
int _a;
};
A* p = new A(10);
使用小括号(),这段代码初始化了一个对象成10,并且将地址赋值给指针变量p。如果是A *P=new A;
那么就会用构造函数中的缺省值对_a进行初始化
3.开辟多个空间并且初始化
A* p = new A[5]{1,2,3};
对上述代码进行解释:
2.2 对比new和malloc的特性
-
对于内置类型来说,new和malloc
并没有太大的区别 -
对于自定义类型来说,new会调用
自定义类型的构造函数,而malloc不会 -
new可以初始化变量的内容
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << this << endl;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
int main()
{
// new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构
造函数和析构函数
A* p1 = (A*)malloc(sizeof(A));
A* p2 = new A(1);
free(p1);
delete p2;
}
3.delete
delete对标的就是c语言中的free,把开辟后不需要再使用的空间返给操作系统。
3.1 delete的使用方法
1.直接delete
int* p = new int(10);
//使用指针p
delete p;
当new堆区空间时只开辟了一份空间
释放空间时直接使用delete即可
2. delete []+开辟的空间名称
int* p = new int[10]{1,2,3,4};
//使用指针p
delete[] p;
当new使用方括号[]开辟多个空间时
delete也要对应的加上[]来释放空间
否则会出错
3.2 对比delete和free的特性
delete特性:
-
对于内置类型,delete和free没有区别
-
对于自定义类型,delete会调用
自定义类型的析构函数,而free不会 -
delete面对不同的情况需要加上[ ]
然而free不用考虑
对于自定义类型来说,有可能类中有指针指向一块堆区
如果不调用析构函数释放这块空间,直接用free释放掉对象的空间,那么这块空间就会内存泄漏!
4.operator new与operator delete函数
那么c++中的new和delete到底是如何开辟空间的呢?
new在底层调用了operator new这个函数重载。
注意:operator new和operator delete这两个函数都是全局函数
库中的operator new实现方式
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
void *p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{
// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
可以发现,new的底层实际上是,
使用了malloc来实现开辟空间
开辟空间成功,会返回指向此空间的指针
开辟空间失败,会抛异常(异常后面再讲)
delete释放空间,是delete底层调用了operator delete这个函数
operator delete的底层代码实现:
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
void operator delete(void *pUserData)
{
_CrtMemBlockHeader * pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK);
__TRY
pHead = pHdr(pUserData);
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg( pUserData, pHead->nBlockUse );
__FINALLY
_munlock(_HEAP_LOCK);
__END_TRY_FINALLY
return;
}
这里看不懂没关系,但是只要看到这里有一个_free_dbg这个函数,他就是free函数的宏替换
说白了就是,delete底层就是调用free来释放空间
5.new和delete的实现原理
5.1 内置类型
如果申请的是内置类型的空间, new 和 malloc , delete 和 free 基本类似,不同的地方是: new/delete 申请和 释放的是单个元素的空间,new[] 和 delete[] 申请的是连续空间,而且 new 在申请空间失败时会抛异常, malloc会返回 NULL 。5.2 自定义类型
new 的原理 1. 调用 operator new 函数申请空间 2. 在申请的空间上执行构造函数,完成对象的构造 delete 的原理 1. 在空间上执行析构函数,完成对象中资源的清理工作 2. 调用 operator delete 函数释放对象的空间 new T[N] 的原理 1. 调用 operator new[] 函数,在 operator new[] 中实际调用 operator new 函数完成 N 个对象空间的申 请 2.在申请的空间上执行 N 次构造函数 delete[] 的原理 1. 在释放的对象空间上执行 N 次析构函数,完成 N 个对象中资源的清理 2. 调用 operator delete[] 释放空间,实际在 operator delete[] 中调用 operator delete 来释放空间6.总结与拓展
此章总结完,就可以去new一个对象了
并且C++和C语言中的内存管理区别
是面试中的常考点,和指针与引用的区别
俗称"面试山上的看门二虎"
拓展1:
malloc/free 和 new/delete 的区别 malloc/free和new/delete的共同点是 :都是从堆上申请空间,并且需要用户手动释放。不同的地方是: 1. malloc 和 free 是函数, new 和 delete 是操作符 2. malloc 申请的空间不会初始化, new 可以初始化 3. malloc 申请空间时,需要手动计算空间大小并传递, new 只需在其后跟上空间的类型即可, 如果是多个 对象,[] 中指定对象个数即可 4. malloc 的返回值为 void*, 在使用时必须强转, new 不需要,因为 new 后跟的是空间的类型 5. malloc 申请空间失败时,返回的是 NULL ,因此使用时必须判空, new 不需要,但是 new 需要捕获异常 6. 申请自定义类型对象时, malloc/free 只会开辟空间,不会调用构造函数与析构函数,而 new 在申请空间 后会调用构造函数完成对象的初始化,delete 在释放空间前会调用析构函数完成空间中资源的清理拓展2:
什么是内存泄漏,内存泄漏的危害 什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不 是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而 造成了内存的浪费。 内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会 导致响应越来越慢,最终卡死。更多关于内存泄漏的内容:
参考下面两篇文章:内存泄漏_百度百科,内存泄漏概念和种类_内存漏洞的种类-CSDN博客
标签:free,--,c++,operator,内存,空间,new,delete From: https://blog.csdn.net/weixin_62196764/article/details/139332354下期预告:模版初阶