new与delete用法详解与底层原理,operator new与operator delete函数,定位new与内存泄漏介绍等

news2024/10/2 14:28:23

tips

  1. 其实进程运行起来或者说程序运行起来都是去执行函数,任务就是不断的去执行函数。C++的入口就是main函数,然后在这个函数当中可能碰到程序某些调用其他函数的语句就去调用其他函数。在全局的区域可以去创建变量,定义函数,但就是不可以去具体的执行某个语句(比如说想要在全区去调用函数)那是不可能的,因为根本就执行不到那边,这是一个原则性的错误。
  2. cin,cout能够自动识别类型的内幕,主要就是说在运算符重载的时候用了函数重载(这个内置类型给他分类分开来),所以说看起来好像能够自动识别类型。
  3. 如果说想要用cout去打印指针int*的话,那么打印出来的就是一个地址。
  4. 如果说想要用cout去直接打印指针char的话,那么这时候他会给你打印出一个字符串来,他碰到\0才会停下打印。如果说去打印这个char指针的解引用的话,打印出来的就是一个字符。

new/delete出现的原因

  1. 在c当中,我们如果需要向内存的堆区去动态申请开辟空间的话,我们一般用的配套选择都是malloc与free。
  2. 但在实际过程当中,malloc与free还是会有很多缺陷与不方便的地方。所以说c++发明出了new与delete。
  3. 我们首先来谈一谈内置类型,对于那些内置类型的变量与数组的内存动态申请资源的话,其实两者之间的差距并没有特别的明显,可以说基本上没有任何区别。
  4. 但是当这个类型涉及到自定义类型的时候,比如说我们需要为一个自定义类型的变量或者说自定义类型变量数组在内存的堆区上面去动态申请内存资源的话,仅仅用malloc与free不仅只能单单的申请出这么一块空间出来,而不能够及时的进行初始化,并且等到程序运行结束的时候对于这个自定义类型变量当中可能需要进行资源的清理,free的话是直接把那块申请出来的内存堆区去空间给释放掉,他并不能够达到我们的资源清理的一个效果。所以说对于自定义类型的变量也好,数组也好,malloc与free都不太行了,这就是new与delete出现的原因

new的用法详解

在这里插入图片描述

delete的用法详解

  1. 其实就是跟new配套着去使用,如果说申请的是一个变量的空间,那么就直接delete指针;
delete ptr1;
  1. 如果说是申请了一个数组的堆区空间,那么就直接delete[ ] 指针
delete[] ptr2;

new底层原理与operator new库函数

在这里插入图片描述
我们现在讨论的是针对于自定义类型变量(举个例子嘛)

  1. 我们再来比较一下malloc与new,你会发现c语言当中的malloc它只会负责去开空间,而对于new来说,他不仅会帮你把内存堆去的空间开好,(因为你这个内存堆取的空间实际上相当于就是一个实例化对象),所以说他还会去调用构造函数。这个就是new相对于malloc的独特优秀之处。
  2. 但无论怎么样,这个new去完成任务的时候首先也还是得去向内存地区开一块空间,那malloc刚好就是负责去向内存堆区开辟空间的,有现成的,我为什么不去用呢?所以这里new的部分任务(开空间)就是去用现成的malloc。
  3. 但是又不能简简单单的完全用malloc去完成new的前部分任务(开空间),因为面向对象的语言都有一个特点:就是当处理失败的时候,他不喜欢像c语言那样去返回值:-1, NULL…他喜欢的是抛异常(这个异常是需要去捕获的),所以说首先在malloc开空间的基础上再添加一些抛异常的机制,这就完成了new的前部分任务(开辟堆区空间),然后把这个过程给他封装成一个函数,就是operator new(这个不是直接的运算符重载,它是一个全局函数,是在库里面的一个函数),所以说现在我们就正式知道了,new开空间其实就是去调用函数operator new。
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);
}

汇编验证:
在这里插入图片描述

delete底层原理与operator delete库函数

在这里插入图片描述

  1. 这个delete操作符实际上它的任务也分为两个部分。
  2. 首先必须先要去执行这个自定义类型实例化对象的析构函数,将动态申请的资源该释放的先释放掉,免得造成内存泄露。
  3. 然后接下来再去用free去释放一下之前用new申请的一个堆区空间。在这个过程当中封装成了一个函数,也是一个库函数:operator delete。这个operator delete函数如果你去看一下它函数的源码的话,你会发现它里面也在执行free罢了。
//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 );  /// ATTENSION!!!
  __FINALLY
    _munlock(_HEAP_LOCK);  /* release other threads */
  __END_TRY_FINALLY
  return;
}
  1. 这边补充一下:从库里面的源码发现,C语言当中的free他实际上是个宏函数:
/*
free的实现
*/
#define  free(p)        _free_dbg(p, _NORMAL_BLOCK)

汇编验证:
在这里插入图片描述

举例子说明operator new,构造函数,析构函数,operator delete 四者顺序关系

在这里插入图片描述
在这里插入图片描述

malloc/free与new/delete区别与相关总结

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

定位new显示调用构造函数

  1. 假设现在我为一个实例化对象在内存的堆区上面去申请开辟了一块空间。但是我就是仅仅开辟了一块空间,我没有去调用构造函数,对于这个属于实例化对象的内存空间进行初始化。这也从侧面反映我此时此刻开辟内存堆区空间并不使用new
  2. 然后此刻的状况就是单纯的开辟了一块内存堆区空间,并且这个内存堆区的空间是属于一个实例化对象。
  3. 此时此刻好比实例化对象已经创建出来了,按道理来说应该是要一语双关去隐式调用构造函数进行一个初始化操作,但现在由于情况特殊,完不成。因为我是向内存堆区申请一块实例化对象的内存空间,而不是像以往那样在栈上创建一个实例化对象。
  4. 这时候我可以用定位new去显示调用构造函数。语法格式如下:在这里插入图片描述
  5. 值得注意的是,但我需要去释放这块实例化对象的堆区空间的时候,由于可能这个实例化对象动态申请了资源,因此先需要去调用析构函数,这时候这个析构函数也是需要我手动去显示调用。
  6. 实例模拟:
#include <iostream>
#include <stdlib.h>
using namespace std;
class Stack
{
public:
	Stack(int capacity)
		:_size(0)
		,_capacity(capacity)
	{
		_p = (int*)malloc(sizeof(int) * _capacity);
		if (_p == nullptr)
		{
			perror("malloc failed");
			return;
		}
	}
	~Stack()
	{
		free(_p);
	}
private:
	int _size;
	int _capacity;
	int* _p;
};
int main()
{
	Stack* ps = (Stack*)malloc(sizeof(Stack));
	if (ps == nullptr)
	{
		perror("malloc failed");
		return 0;
	}
	new(ps)Stack(10);
	ps->~Stack();
	return 0;
}

内存泄漏

在这里插入图片描述
在这里插入图片描述
一个进程正常结束之后,这些动态申请的内存资源就算你没有释放的话,操作系统也会自己给他解掉,所以说我们平时写的程序的话,内存泄露其实影响不太大;真正要命的就是在那些服务程序里面,或者说游戏程序里面,因为他那个程序是24×7不停机的,长期的内存泄露下去的话,将会产生各种各样的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/544579.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构-栈,队列

栈&#xff0c;队列 1 知识框架2 栈2.1 顺序栈2.2 链式栈 3 队列3.1 顺序队列3.2 循环队列3.3 链式队列 4 数组4.1 二维数组4.2 特殊数组的压缩存储 1 知识框架 2 栈 定义&#xff1a;只允许在一端进行插入或删除得到线性表 栈的数学性质&#xff1a;n个不同元素进栈&#xff…

phpWord使用模板填充数据:包含表格及嵌套表格(多个表格/循环表格)

参考文档 模板处理 基础使用 安装过程省略&#xff0c;首先加载模板: $templateProcessor new TemplateProcessor(ROOT_PATH . uploads/template/自动生成模板.docx); 完整保存流程 首先&#xff0c;要进行测试&#xff0c;起码能够写一个完整的demo&#xff0c;以下是我测…

实验三---面向对象分析与设计——UML用例图与活动图

一、实验目的&#xff1a; 掌握面向对象分析中用例建模的基本思想&#xff0c;学会识别参与者和用例&#xff0c;掌握UML用例图的绘制方法&#xff0c;学会编写用例说明&#xff1b;了解活动图的作用和组成元素&#xff0c;掌握UML活动图的绘制方法&#xff0c;学会使用活动图来…

秒懂算法 | KMP算法(Java描述)

Knuth-Morris-Pratt 算法&#xff08;简称 KMP&#xff09;是由高德纳&#xff08;Donald Ervin Knuth&#xff09;和沃恩普拉特在1974年构思&#xff0c;同年詹姆斯H莫里斯也独立地设计出该算法&#xff0c;最终三人于1977年联合发表。该算法较Brute-Force算法有较大改进&…

门电路OD门

漏极开路输出的门电路&#xff08;OD门&#xff09; 为了满足输出电平的变换&#xff0c;输出大负载电流&#xff0c;以及实现“线与”功能&#xff0c;将CMOS门电路的输出级做成漏极开路的形式&#xff0c;称为漏极开路输出的门电路&#xff0c;简称OD&#xff08;Open&#x…

【JVM】1. JVM与Java体系结构

文章目录 1.1. 前言&#x1f349;1.2. 参考书目&#x1f349;1.3. Java及JVM简介&#x1f349;1.4. Java发展的重大事件&#x1f349;1.5. 虚拟机与Java虚拟机&#x1f349;1.6. JVM的整体结构&#x1f349;1.7. Java代码执行流程&#x1f349;1.8. JVM的架构模型&#x1f349;…

4. QT中的鼠标键盘事件 --- 鼠标拖拽案例

1. 说明 在QT的控件或者窗口当中&#xff0c;如果对于当前鼠标或者键盘的功能需要自己定义&#xff0c;可以重写父类当中对应虚函数&#xff0c;主要包括以下几个&#xff1a; //键盘按键按下 virtual void keyPressEvent(QKeyEvent *event); //键盘按键抬起 virtual void ke…

为什么C++这么复杂还不被淘汰?

C是一门广泛使用的编程语言&#xff0c;主要用于系统和应用程序的开发。尽管C具有一些复杂的语法和概念&#xff0c;但它仍然是编程界的重量级选手&#xff0c;在编程语言排行榜中一直位居前列。为什么C这么复杂还不被淘汰呢&#xff1f; C有以下优势 1、C具有高性能 C是一门编…

unity进阶学习笔记:photonServer测试

photonServer是由photon发布的一个网络框架&#xff0c;其封装了UDP和TCP通信机制让用户可以直接调用API实现网络游戏通信 1 photonServer下载安装 进入Photon官网的SDK选项&#xff0c;选择下载Server。目前Server版本已经更新到v5&#xff0c;这里我为了和教程保持一致下载…

Unittest接口测试生成报告和日志方法

HTML报告 直接把HTMLTestRunner.py放入工程目录即可报告脚本封装 #HTNL格式报告now datetime.datetime.now().strftime(%Y-%m-%d_%H_%M_%S)htmlreport reportpath "/" now r"result.html"print("测试报告生成地址&#xff1a;%s"% htmlre…

Revit干货 | 系统族、内建族、可载入族一次性搞清楚!

对于使用人数较多的revit软件&#xff0c;其中的许多概念与我们常用的CAD完全不同&#xff0c;以至于让许多工程师觉得revit软件有点高深莫测&#xff0c;不可琢磨&#xff0c;从而有了抗拒心理。 Revit软件中的重要概念&#xff1a; “族”是revit软件中的很重要也很基本的概念…

程序的各种段以及堆栈相关问题

C中一般有三种变量&#xff1a; 局部变量全局变量静态变量 C中一般有五个内存段&#xff1a; 代码段 也叫文本段&#xff0c;包含frequently executed code通常是只读的&#xff08;未了避免程序被错误改写&#xff09;代码段是不包含程序变量&#xff08;如局部变量、全局变…

【数据结构】带头双向链表,真正的六边形战士

文章目录 概要整体架构流程小结 概要 *数据结构中的链表在实际开发中应用非常广泛&#xff0c;但写一个链表并不是一件简单的事情。链表有八种结构&#xff0c;对于刚入门的新手来说&#xff0c;往往会先经历单链表的折磨。 而今天我要讲的带头双向链表非常适合新手学习&#…

C++6.类和对象(下)

1.友元函数&#xff0c;一般现在类的最上面。 2.函数的参数中&#xff0c;如果不改变&#xff0c;尽量加上const修饰。 3.对于自定义类型&#xff0c;使用运算符进行操作基本上都要用运算符重载&#xff0c;但是有些运算符重载会默认自动生成。 4.初始化列表&#xff0c;是成…

【wpf】列表类,用相对源时,如何绑定到子项

前言 在之前的一篇文章 &#xff1a;《【wpf】深度解析&#xff0c;Binding是如何寻找数据源的》https://blog.csdn.net/songhuangong123/article/details/126195727#:~:text%E3%80%90wpf%E3%80%91%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90%EF%BC%8CBinding%E6%98%AF%E5%A6%82%E4…

读书|林曦:她把自己的生活,过成了无用但丰盈的美学

时代在以加速度的方式变化&#xff0c;让人难以从容。而当我们陷于横向的比较系统&#xff0c;权衡着卷、躺、润时&#xff0c;也有人在探寻另一条纵向的路——向古人学习&#xff0c;以传统美学关照和滋养当下生活。      立夏之际&#xff0c;水墨画家林曦的新作《无用之…

33岁跳槽无路,濒临绝望之际受贵人指点,成功上岸阿里(测试岗)

写在前面 马上过34岁生日了&#xff0c;和大家聊聊最近的情况&#xff0c;半年前还在迷茫该学什么&#xff0c;怎样才能走出现在的困境&#xff0c;半年后已经成功上岸阿里&#xff0c;感谢在这期间帮助我的每一个人 开始 30多岁工作的时候总是有种力不从心的感觉&#xff0…

网络安全工程师需要考什么证吗?

目前网络安全行业&#xff0c;国内都有哪些证书可以考。 一、CISP-PTE &#xff08;国家注册渗透测试工程师&#xff09; CISP-PTE即注册信息安全渗透测试工程师&#xff0c;该证书由中国信息安全测评中心颁发&#xff0c;证书是国内唯一认可的渗透测试认证&#xff0c;专业性…

AIOps社区低代码项目火热报名中|中科院开源之夏2023,万元现金等你来拿!

活动介绍 开源之夏是由中科院软件所“开源软件供应链点亮计划”发起并长期支持的一项暑期开源活动&#xff0c;旨在鼓励在校学生积极参与开源软件的开发维护&#xff0c;培养和发掘更多优秀的开发者&#xff0c;促进优秀开源软件社区的蓬勃发展&#xff0c;助力开源软件供应链…

告别Excel,免费大数据分析与可视化工具,让你的论文图表“高大上”

数据分析工具很多&#xff0c;可以分为表格、数据库、BI工具、编程等四大工具。每个大类又有很多的工具&#xff0c;例如表格包括Excel、WPS、Google Sheets、Airtable等。编程工具包括Python和R。 搞科研几年了&#xff0c;笔者一直都是在使用Excel做数据分析和可视化&#xf…