首页 > 系统相关 >【c++基础(五)】内存管理--new

【c++基础(五)】内存管理--new

时间:2024-05-30 19:58:16浏览次数:25  
标签:free -- c++ operator 内存 空间 new delete

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 newoperator 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

相关文章

  • 【c++基础(四)】类和对象下--初始化列表等概念
    1.前言类和对象到这里基本已经接近尾声,本篇文章主要介绍一些与类和对象有关的相关细节,在后续使用类和对象中也有可能用的到。本章重点:本篇文章重点讲解初始化列表,友元,匿名对象和类中的static成员,以及类中的内部类的概念。 2.初始化列表 在谈论初始化列表之前就要再次......
  • [JSOI2015] 染色问题
    [JSOI2015]染色问题题目描述萌萌家有一个棋盘,这个棋盘是一个\(n\timesm\)的矩形,分成\(n\)行\(m\)列共\(n\timesm\)个小方格。现在萌萌和南南有\(C\)种不同颜色的颜料,他们希望把棋盘用这些颜料染色,并满足以下规定:棋盘的每一个小方格既可以染色(染成\(C\)种颜......
  • uoj项目部署的学习实践和基于JUnit进行的项目测试
    基于JUnit进行的项目测试对不同功能点进行测试:检测忘记密码功能、注册功能能否正常使用脚本文件:registerTest.java1.检测忘记密码功能。事先注册好一个账号用于测试测试步骤:输入账号输入电子邮箱输入验证码1)用例标题:验证码错误情况测试数据:账号2021127电子邮箱2848250......
  • uoj概述
    一、基本工作原理UOJ主要由两部分组成:网页端和测评端。顾名思义,网页端就是用来通过网页与用户交互的,测评端则是在用户发出测评请求时负责测评并将结果发送给网页端的。网页端什么是网页端?顾名思义,就是管网页的部分。网页端又分为网页前端和网页后端。所谓网页前端,就是你打开浏......
  • 答案检查器
    五.答案检查器本文将引导您写一个自定义的checker(chk.cpp)。按照套路,uoj的校验器也应该使用testlib编写。下面是A+BProblem的校验器:#include"testlib.h"intmain(intargc,char*argv[]){registerTestlibCmd(argc,argv);intpans,jans;pans=ouf.readInt();//......
  • 数据检验器
    四.数据检验器uoj的数据检验器(val.cpp)使用testlib。下面是A+BProblem的检验器:#include"testlib.h"usingnamespacestd;intmain(void){registerValidation();inf.readInt(0,1000000000,"A");inf.readSpace();inf.readInt(0,1000000000,"B");in......
  • 特殊需求的配置
    三.特殊需求配置由于很多题目有乱七八糟的配置,uoj用了一些不清真的方法来实现。1.子任务子任务模式中,必须把某个subtest的数据全部通过才能拿到对应的分数。在problem.conf中,可以设置每个子任务在哪个测试点结束,并给每个子任务分配对应的分数。它的写法如下:[n_tests40.........
  • 传统题的配置
    二.传统题配置1.数据对于传统题,上传的×.zip数据包应当包括这些内容:题目配置文件测试数据额外测试数据(包括题面中所给的测试样例)(开启hack)数据检验器(开启hack)标准程序2.题目配置文件题目配置文件应当命名为problem.conf。这是一份配置的样例:[n_tests10n_ex_tests1n......
  • uoj项目部署中题目管理的相关学习与应用
    一.概述1.新建题目和管理界面只有超级管理员有权限新建题目,每次新建题目都必须由超级管理员完成。在题目页面,超级管理员或该题目的管理员可以通过管理按钮进入题目管理界面。题目管理界面分为三个选项卡:编辑:题面编辑页面管理者:题目管理员管理页面数据:题目数据管理页面以及......
  • 基于JUnit进行的项目测试
    基于JUnit进行的项目测试对不同功能点进行测试:检测忘记密码功能、注册功能能否正常使用脚本文件:registerTest.java1.检测忘记密码功能。事先注册好一个账号用于测试测试步骤:输入账号输入电子邮箱输入验证码1)用例标题:验证码错误情况测试数据:账号2021127电子邮箱2848250......