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

news2024/12/23 12:09:02

在这里插入图片描述

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨
🐻推荐专栏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_FINALLY
     return;
}

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.coloradmin.cn/o/879932.html

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

相关文章

网络安全(自学)

想自学网络安全&#xff08;黑客技术&#xff09;首先你得了解什么是网络安全&#xff01;什么是黑客&#xff01; 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全…

数字鸿沟,让气候脆弱者更脆弱

随着科技的飞速发展&#xff0c;数字化正在改变我们的生活方式和社会结构。然而&#xff0c;数字鸿沟&#xff08;Digital Divide&#xff09;这一长期存在的问题&#xff0c;却在某些方面加剧了社会的不平等现象。在此&#xff0c;我们将探讨数字鸿沟如何加剧了气候脆弱者的脆…

帮助中心干货:7步即可在线搞定产品帮助中心!

在产品的生命周期中&#xff0c;帮助中心是一个非常重要的部分&#xff0c;它能够为用户提供必要的信息和解决方案&#xff0c;帮助他们更好地使用产品。如果你正在寻找一种简单高效的方法来在线搭建产品帮助中心&#xff0c;那么这篇干货文章将为你提供7个步骤&#xff0c;让你…

Spring Boot+Redis 实现一个简单的限流器示例

Spring BootRedis 实现一个简单的限流器&#xff0c;限制 文章目录 Spring BootRedis 实现一个简单的限流器&#xff0c;限制0.前言1.基础介绍2.步骤2.1. 引入依赖2.2. 配置文件2.3. 核心源码优化后再优化一下加入布隆过滤器 4.总结5.参考文档6. Redis从入门到精通系列文章 0.前…

【设计模式——学习笔记】23种设计模式——策略模式Strategy(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录 案例引入传统方案实现实现分析 介绍基本介绍登场角色 案例实现案例一类图实现 案例二类图实现问答 策略模式在JDK源码中的使用总结文章说明 案例引入 有各种鸭子&#xff0c;比如野鸭、北京鸭、水鸭等。 鸭子有各种行为&#xff0c;比如走路、叫、飞行等。不同鸭子的…

跨境电商ERP源码选择指南:如何挑选最适合您的方案

在如今充满机遇的跨境电商领域&#xff0c;选择适合自己的ERP源码方案至关重要。然而&#xff0c;众多选择使得挑选变得棘手。作为跨境电商ERP源码领域的专家&#xff0c;我将揭示7个权威建议&#xff0c;帮助您在海量方案中快速、准确地找到最适合您的ERP源码。让我们一起深入…

元宇宙赛道加速破圈 和数软件抓住“元宇宙游戏”发展新风口

当下海外游戏市场仍然具备较大的增长空间。据机构预测&#xff0c;至2025年全球移动游戏市场规模将达1606亿美元&#xff0c;对应2020-2025年复合增长率11&#xff05;。与此同时&#xff0c;随着元宇宙概念持续升温&#xff0c;国内外多家互联网巨头纷纷入场。行业分析平台New…

Android布局【GridLayout】

文章目录 GridLayout概述常见属性子控件属性项目结构主要代码 GridLayout概述 GridLayout也名网格布局,该布局与TableLayout类似&#xff0c;但与其相比&#xff0c;GridLayout会更加的灵活&#xff0c;比如 TableLayout不能将两行进行一个合并&#xff0c;只能将两列进行一个…

新能源汽车电控系统

新能源汽车电控系统主要分为&#xff1a;三电系统电控系统、高压系统电控系统、低压系统电控系统 三电系统电控系统 包括整车控制器、电池管理系统、驱动电机控制器等。 整车控制器VCU 整车控制器作为电动汽车中央控制单元&#xff0c;是整个控制系统的核心&#xff0c;也是…

C#_编码奥秘

什么是编码&#xff1f; 将信息&#xff08;文字、图像、声音、视频、代码&#xff09;使用特定的符号组合表示出来的过程。 任何信息载体都是编码&#xff0c;编码是 信息通信 与 信息处理 技术的基础。 编码与信息通信 长亮三下&#xff08;S&#xff09;&#xff0c;短亮三…

中小企业选择CRM系统需要有哪些功能?

对于中小企业来说&#xff0c;选择一个合适的CRM系统是非常重要的&#xff0c;一款好用的CRM可以帮助企业提高业务效率&#xff0c;获得更多收益。那么&#xff0c;中小企业CRM系统的主要特点有哪些呢&#xff1f;下面我们从四个方面来说说。 1、功能&#xff1a; 功能是指CR…

秦岭地形图、水系图、全景图

来源&#xff1a;头条留白sy&#xff0c;星球研究所等&#xff0c;转自&#xff1a;地理科学研究苑

Python数学函数、字符串和对象

学习目标&#xff1a; 使用math模块中的函数解决数学问题表示和处理字符串和字符使用ASCII和Unicode对字符编码使用ord函数获取一个字符的数值编码以及使用chr函数将一个数值编码转换成一个字符使用转义序列表示特殊字符调用带参数end的print函数使用str函数将数字转换成字符串…

小调查:你的流量卡是在线上买的还是在线下买的?

可能大家都知道&#xff0c;现在不管是线上还是线下都可以办理流量卡&#xff0c;线上的流量卡资费便宜一些&#xff0c;线下的流量卡功能更多一些&#xff0c;那么你是在线上购买的流量卡&#xff0c;还是在线下给我们的流量卡呢&#xff1f; ​ 都知道一分钱一分货&#xff…

电脑屏幕闪烁?别慌!解决方法在这!

“我新买了一台电脑&#xff0c;还没用几天呢&#xff0c;就出现了电脑屏幕闪烁的情况&#xff0c;这让我感到很烦躁。有什么方法可以解决电脑屏幕闪烁的问题呢&#xff1f;” 使用电脑的过程中&#xff0c;我们不难发现电脑屏幕有时候会出现闪烁的情况&#xff0c;这会导致使用…

试卷扫描成电子版方法分享,这个方法不要错过

很多时候&#xff0c;为了方便传输我们需要将试卷扫描成电子版进行存档&#xff0c;以备不时之需。很多小伙伴如果遇到试卷需要扫描转成电子版可能就不知道该如何操作了&#xff0c;其实试卷扫描是一项非常重要的工作&#xff0c;因此需要注意一些方法和细节。以下是试卷扫描成…

一个基于SpringBoot+Vue前后端分离高校心理健康系统详细设计实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

库存管理系统哪个好?亿发云南省大型智能WMS仓储信息解决方案,免费更新

在当今激烈的仓储物流竞争中&#xff0c;企业的成功关键在于加强作业效率和降低话费。随着科技的不断更新&#xff0c;传统仓储方式已逐渐被智能仓储管理系统&#xff08;WMS&#xff09;取代&#xff0c;并逐渐成为行业趋势。大数据时代下&#xff0c;引进行之有效的智能管理系…

Windows系统Git安装教程(详细Git安装过程)

获取Git安装程序 到Git官网下载&#xff0c;网站地址&#xff1a;https://git-scm.com/downloads&#xff0c;如下图&#xff1a; 因为我们是用Windows系统上的浏览器访问的&#xff0c;Git官网自动之别到了我使用的操作系统&#xff0c;所以右侧直接显示下载使用Windows系统的…

容器云平台监控告警体系—— Prometheus发送告警机制

1、概述 在Prometheus的架构中告警被划分为两个部分&#xff0c;在Prometheus Server中定义告警规则以及产生告警&#xff0c;Alertmanager组件则用于处理这些由Prometheus产生的告警。本文主要讲解Prometheus发送告警机制也就是在Prometheus Server中定义告警规则和产生告警部…