“new出对象“原理的深层解密

在这里插入图片描述

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨
🐻推荐专栏1: 🍔🍟🌯C语言初阶
🐻推荐专栏2: 🍔🍟🌯C语言进阶
🔑个人信条: 🌵知行合一
🍉本篇简介:>:讲解C++中的有关内存管理知识,如何new出对象?
金句分享:
✨如果事与愿违,请相信另有安排.✨

前言

讲解C++中有关new的知识,与malloc进行对比,以及深入探索new的实现原理.

目录

  • 前言
  • 一、malloc和new的使用
    • 1.1 new创建内置类型(int等)
    • 1.2 new创建数组
    • 1.3 创建对象
    • 1.4 异常处理
  • 二、malloc和new的区别:(面试热门)
  • 三、new和delete的深层解密
    • 3.1 解密实现原理
    • 3.2 通过汇编指令验证

一、malloc和new的使用

C语言阶段,我们习惯使用malloc向内存申请空间,但是在C++阶段,我们习惯用new在动态内存中创建对象,为什么呢?

1.1 new创建内置类型(int等)

在创建内置类型时,new只是不需要进行强转和计算内置类型的大小,看起来更加简洁,方便.

	//malloc申请内置类型int* p1 = (int*)malloc(sizeof(int));free(p1);//new对比int* ptr1 = new int;delete ptr1;

1.2 new创建数组

new + 对象的类型 + [个数] + (初始化的值)

new + 对象的类型 + [个数] + {num1,num2,…}

需要注意的是,连续的多个空间须使用new[]delete[]搭配

	//申请数组int* p3 = (int*)malloc(sizeof(int) * 10);//赋值for (int i = 0; i < 10; i++){p3[i] = i;}//打印for (int i = 0; i < 10; i++){cout << p3[i] << " ";}cout << endl;// new创建数组int* ptr3 = new int[10]{0,1,2,3,4,5,6,7,8,9};for (int i = 0; i < 10; i++){cout << ptr3[i] << " ";}//释放free(p3);delete[] ptr3;

1.3 创建对象

如何使用new进行创建对象?

#include <iostream>
using namespace std;
#include<stdlib.h>class Date
{
public:Date():_year(2020),_month(6),_day(6){cout << "A()" << endl;}void print(){cout << _year << "-" << _month << "-" << _day << endl;}~Date(){cout << "~A()" << endl;free(_a);}
private:int _year;int _month;int _day;int* _a=nullptr;
};int main()
{//malloc出对象Date* d1 = (Date*)malloc(sizeof(Date));d1->print();free(d1);//new出对象Date* d2 = new Date;d2->print();delete d2;return 0;
}

运行结果:

-842150451–842150451–842150451
A()
2020-6-6
~A()

通过上段代码我们发现,malloc只是进行开空间的操作,对象并没有得到初始化操作.
new则是在开空间的同时,会调用对象的构造函数,将对象进行初始化.

free只是进行简单的释放申请的空间,如果对象中存在动态申请的成员,则无法进行释放.
delete会在释放申请的对象空间的同时,调用对象的析构函数,彻底的完成空间的清理工作.

1.4 异常处理

对于malloc函数,当malloc申请内存空间失败的时候,会返回一个NULL指针.
我们通常通过判断返回值是否为NULL来判断是否申请成功.

	int* a = (int*)malloc(10000* sizeof(int));if (a == NULL){perror("malloc a fail");//申请失败时,打印错误信息return 0;}

new失败不会返回NULL,而是通过抛出异常.
C++中,可以使用try-catch语句来捕获new操作符抛出的异常。new操作符在内存分配过程中如果失败,会抛出一个bad_alloc异常。

示例代码:

try {int* myArray = new int[10000]; // 分配一个包含10000个整数的数组// ...delete[] myArray; 
}
catch (const std::bad_alloc& e) {// 处理内存分配失败的异常std::cout << "内存分配失败: " << e.what() << std::endl;
}

在上述代码中,new操作符用于分配一个包含10000个整数的数组。如果内存分配失败,将抛出一个bad_alloc异常。catch语句块接收这个异常,并执行相应的处理代码。在这个示例中,异常被捕获后会打印一条错误消息。

需要注意的是,catch语句块中的参数类型应为const std::bad_alloc&,因为bad_alloc是标准异常类,它派生自std::exception,通常以常量引用的形式传递给异常处理代码。

二、malloc和new的区别:(面试热门)

C++中,mallocnew都用于在堆上分配内存,但有一些重要的区别。

  1. 语法和类型安全性mallocfree是函数,newdelete是操作符
    (1)malloc是C语言中的函数,malloc需要指定要分配的内存大小,并返回一个指向未初始化内存块的指针。
    (2)newC++中的运算符new可以直接在创建对象时进行初始化,并返回一个指向已经构造的对象的指针。new操作符会执行类型检查,确保分配的内存与对象类型匹配。

  2. 构造函数和析构函数调用
    (1)使用new分配内存时,会自动调用对象的构造函数进行初始化。
    (2)使用malloc分配内存时,不会调用对象的构造函数,需要手动调用构造函数初始化对象。
    (3)同样,使用delete释放new分配的内存时,会自动调用析构函数进行清理工作。而使用free释放malloc分配的内存时,不会自动调用析构函数,需要手动执行清理操作。

  3. 内存大小计算
    (1)使用malloc分配内存时,需要显式指定要分配的内存块的大小,以字节为单位。
    (2)使用new分配单个对象时,编译器会自动计算所需的内存大小,以对象的类型为基础。对于数组对象,需要使用new[]delete[],同样会自动计算所需的内存。

  4. 异常处理new在分配内存失败时,会抛出std::bad_alloc异常,而malloc在分配内存失败时,返回NULL指针。

  5. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型

总的来说,new相对于malloc提供了更高级的、更安全的内存分配方式,能够自动调用构造函数和析构函数,执行类型检查,并提供异常处理。因此,在C++中,推荐使用newdelete来进行动态内存分配和释放。如果你需要使用C语言的库或与C代码进行交互,可以使用mallocfree

三、new和delete的深层解密

3.1 解密实现原理

学到这里,我们知道new会代用构造函数,还会抛出异常,那它究竟是怎么实现的呢?
在这里插入图片描述

operator new的实现

void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
void *p;
while ((p = malloc(size)) == 0)//通过mallo开空间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 );//调用了free函数__FINALLY_munlock(_HEAP_LOCK);  /* release other threads */__END_TRY_FINALLYreturn;
}

free的实现就是一个宏定义_free_dbg(p, _NORMAL_BLOCK)

#define   free(p)               _free_dbg(p, _NORMAL_BLOCK)

我们可以直接调用operator newoperator delete函数.

void test1()
{A* a1 = (A*)operator new (sizeof(A));A* a2 = (A*)malloc (sizeof(A));operator delete(a1);free(a2);
}
int main()
{test1();return 0;
}

发现operator new 的使用和malloc没什么区别,
只是一个抛异常.
一个返回NULL.
在这里插入图片描述

3.2 通过汇编指令验证

void test1()
{A* a1 = new A;delete a1;
}

通过调试窗口的反汇编窗口,我们查看A* a1 = new A;对应的汇编指令:
在这里插入图片描述
会发现,new操作符果然是调用operator new +构造函数.

查看delete操作符,由于vs编译器进行了再封装,我们需要进到下面这条指令里面去看:
在这里插入图片描述

不难发现,delete操作符=调用析构函数+调用operator delete函数
在这里插入图片描述

好的,本篇有关new操作符和delete操作符的相关知识就讲到这里了,希望对大家有所帮助.
如果觉得文章有帮助的话,可以来个一键三连吗?
在这里插入图片描述

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

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

相关文章

正规的股票杠杆公司_杠杆公司排名(2023年版的)

本文将介绍一些正规的股票杠杆公司&#xff0c;并重点介绍配先查网站的特点&#xff0c;该网站是一家专业查询实盘杠杆平台的网站&#xff0c;提供相关信息和参考。 杠杆公司排名&#xff08;2023年版的&#xff09;&#xff1a;广盛网、一鼎盈、尚红网、盛多网、红腾网、富灯…

高级AI赋能Fortinet FortiXDR解决方案

扩展检测和响应 (XDR&#xff1a;Extended Detection and Response) 解决方案旨在帮助组织整合分布式安全技术&#xff0c;更有效地识别和响应活动的威胁。虽然 XDR 是一种新的技术概念&#xff0c;但其构建基础是端点检测和响应 (EDR&#xff1a;Endpoint Detection and Respo…

web即时通讯系统与APP即时通讯系统有什么区别?

随着互联网的不断发展&#xff0c;即时通讯技术也在不断地完善和发展&#xff0c;其中Web即时通讯系统和APP即时通讯系统成为了人们广泛使用的两种通讯方式。那么&#xff0c;这两者之间究竟有什么区别呢&#xff1f;在本文中&#xff0c;我们将为您详细介绍这两种通讯方式的区…

如何将labelImg打包成exe

最近整理一下数据标注这块的内容&#xff0c;在目标检测和目标分割里面用的最多的标注工具labelimg&#xff0c;labelme labelimg主要用于目标检测领域制作自己的数据集&#xff0c;如&#xff1a;YOLO系列目标检测模型 labelme主要用于图像分割领域制作自己的数据集&#xf…

如何仿写简易tomcat 实现思路+代码详细讲解

仿写之前&#xff0c;我们要搞清楚都要用到哪些技术 自定义注解&#xff0c;比如Tomcat使用的是Servlet&#xff0c;我们可以定义一个自己的MyServlet构造请求体和返回体&#xff0c;比如tomcat使用HttpRequest&#xff0c;我们可以自己定义myHttpRequestjava去遍历一个指定目…

数据结构——链表详解

链表 文章目录 链表前言认识链表单链表结构图带头单循环链表结构图双向循环链表结构图带头双向循环链表结构图 链表特点 链表实现(带头双向循环链表实现)链表结构体(1) 新建头节点(2) 建立新节点(3)尾部插入节点(4)删除节点(5)头部插入节点(6) 头删节点(7) 寻找节点(8) pos位置…

APP外包开发原生和H5的区别

原生开发和H5开发是两种不同的方法&#xff0c;用于创建移动应用程序。它们具有各自的特点、优势和劣势&#xff0c;适用于不同的应用场景。以下是原生开发和H5开发之间的一些主要区别&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发…

未来公文的智能化进程

随着技术的飞速发展&#xff0c;公文——这个有着悠久历史的官方沟通方式&#xff0c;也正逐步走向智能化的未来。自动化、人工智能、区块链...这些现代科技正重塑我们的公文制度&#xff0c;让其变得更加高效、安全和智慧。 1.语义理解与自动生成 通过深度学习和NLP&#xff…

从零基础到精通IT:探索高效学习路径与成功案例

文章目录 导语&#xff1a;第一步&#xff1a;明确学习目标与方向选择适合的IT方向设定具体的学习目标咨询和调研 第二步&#xff1a;系统学习基础知识选择适合的编程语言学习数据结构和算法掌握操作系统和计算机网络基础 第三步&#xff1a;实践项目锻炼技能选择合适的项目编写…

Redis——哨兵模式(docker部署redis哨兵)+缓存穿透和雪崩

哨兵模式 自动选取主机的模式。 概述 主从切换技术的方法是:当主服务器宕机后&#xff0c;需要手动把一台从服务器切换为主服务器&#xff0c;这就需要人工干预&#xff0c;费事费力&#xff0c;还会造成段时间内服务不可用。这不是一种推荐的方式&#xff0c;更多时候&…

前端开发怎么解决性能优化的问题? - 易智编译EaseEditing

前端性能优化是确保网站或应用在加载速度、响应性和用户体验等方面达到最佳状态的关键任务。以下是一些解决前端性能优化问题的方法&#xff1a; 压缩和合并代码&#xff1a; 压缩和合并CSS、JavaScript和HTML文件可以减少文件大小&#xff0c;加快加载速度。使用压缩工具&am…

vue vs react

vue 简介&#xff1a;渐进式 JavaScript 框架 来源&#xff1a;最初由 Evan You &#xff08;尤雨溪&#xff09;于2014年开发。Evan You之前在Google研究过AngularJS&#xff0c;并提取了Angular的部分特性以提供一个更轻量级的框架 版本&#xff1a; vue 1x&#xff1a;2014…

协同过滤推荐算法-基于Django+mysql的智能水果销售系统设计(可做计算机毕设)

随着科技的不断发展&#xff0c;智能化已经成为各行各业的趋势&#xff0c;水果销售行业也不例外。智能水果销售系统就是应运而生的一种智能化解决方案&#xff0c;它可以为用户提供更加便捷、高效的购物体验。其中&#xff0c;系统模块是智能水果销售系统的重要组成部分。 系…

【Apollo学习笔记】—— Planning模块

前言 本文记录学习planning模块时的一些笔记&#xff0c;总体流程参照https://zhuanlan.zhihu.com/p/61982682中的流程图&#xff0c;如上图所示。 planning_component modules/planning/planning_component.cc PlanningComponent::Init部分首先完成规划模式的选择&#xff…

【Linux】POSIX信号量和基于环形队列的生产消费者模型

目录 写在前面的话 什么是POSIX信号量 POSIX信号量的使用 基于环形队列的生产消费者模型 写在前面的话 本文章主要先介绍POSIX信号量&#xff0c;以及一些接口的使用&#xff0c;然后再编码设计一个基于环形队列的生产消费者模型来使用这些接口。 讲解POSIX信号量时&#x…

windows结束explorer进程后桌面白屏解决

背景 结束进程时一不小心一起删掉explorer.exe &#xff0c;这个文件结束桌面就一片白 &#xff0c; 解决&#xff1a; 不要关机&#xff0c;同时按键盘上ctrlshiftesc ,重新进入任务管理器&#xff0c;接着点“进程”选项&#xff0c;按左上角文件选项&#xff0c;进入下拉菜单…

备份或同步数据?跨国大文件传输的不同需求与解决方案

信息化时代的到来&#xff0c;使得许多个人、组织、企业在日常生活中都需要对数据进行备份或同步。但不同的应用场景和需求&#xff0c;也需要不同的备份和同步方式。而在跨国大文件传输方面&#xff0c;更是需要根据不同需求选择合适的传输方案。下面将分别介绍备份与同步数据…

BeanFactoryApplicationContext之间的关系

1**.BeanFactory与ApplicationContext之间的关系** &#xff08;1&#xff09;从继承关系上来看&#xff1a; ​ BeanFactory它是ApplicationContext 的父接口 &#xff08;2&#xff09;从功能上来看&#xff1a; ​ BeanFactory才是spring中的核心容器&#xff0c;而Appli…

【数学建模】-- 数学规划模型

概述&#xff1a; 什么是数学规划&#xff1f; 数学建模中的数学规划是指利用数学方法和技巧对问题进行数学建模&#xff0c;并通过数学规划模型求解最优解的过程。数学规划是一种数学优化方法&#xff0c;旨在找到使目标函数达到最大值或最小值的变量取值&#xff0c;同时满足…

VGG简单学习

VGG简单学习 简单介绍 在AlexNet网络的基础上&#xff0c;为了设计深层神经网络&#xff0c;牛津大学设计了VGG网络,采用块的设计理念&#xff0c;将AlexNet中多个重复的卷积层和池化层组成一个块 论文中&#xff0c;使用3x3卷积核&#xff0c;padding1的卷积层 和带有2x2的汇…