C++ ------ new关键字和delete关键字

news2024/9/24 19:17:27

文章目录

  • C/C++内存分布
    • C++内存管理方式
  • operator new 与 operator delete 函数
  • new和delete的实现原理
    • 内置类型
    • 自定义类型
  • 定位new表达式

C/C++内存分布

我们来看下面的一个题目:

int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
 static int staticVar = 1;
 int localVar = 1;
 int num1[10] = { 1, 2, 3, 4 };
 char char2[] = "abcd";
 const char* pChar3 = "abcd";
 int* ptr1 = (int*)malloc(sizeof(int) * 4);
 int* ptr2 = (int*)calloc(4, sizeof(int));
 int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
 free(ptr1);
 free(ptr3);
}

我们来看一下上面的变量是在内存块中的哪个区的。

  1. 选择题:
    选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
    globalVar在哪里?C staticGlobalVar在哪里?C
    staticVar在哪里?C localVar在哪里?A
    num1 在哪里?A
    char2在哪里?A__ *char2在哪里?A_
    pChar3在哪里?A *pChar3在哪里?D__
    ptr1在哪里?A *ptr1在哪里?B__
  2. 填空题:
    sizeof(num1) = 40;
    sizeof(char2) = 5; strlen(char2) = 4;
    sizeof(pChar3) = 4or8; strlen(pChar3) = 4__;
    sizeof(ptr1) = 4or8;
    在C语言中我们讲过内存可以划分为堆区,栈区,静态区和常量区,下图为数据所在区域的划分:

在这里插入图片描述

C++内存管理方式

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式,通过new和delete操作符进行动态内存管理。new/malloc出了用法上面,其他方面没什么区别。下面代码是new和delete关键字的使用方法:
对内置类型

int main()
{
	//new/delete操作内置类型
	//动态申请一个int类型的空间并对空间进行初始化
	int* ptr = new int(1);

	//动态申请一个10个int类型的数组并初始化为0
	int* ptr1 = new int[10]{ 0 };

	//删除一个int类型空间
	delete ptr;
	//删除数组
	delete[] ptr1;
	return 0;
}

需要注意的是:我们尽量和C语言的内存管理区别开,一定要配套使用。为了不必要的麻烦我们尽量写成new和delete是一对,malloc和free是一对。

对自定义类型

class Stu
{
public:
	Stu(char name, char sex, int age)
	{
		cout << "Stu(char name, char sex, int age)" << endl;
		_name = name;
		_sex = sex;
		_age = age;
	}
	~Stu()
	{
		cout << "~Stu()" << endl;
	}
private:
	char _name;
	char _sex;
	int _age;

};

int main()
{
	Stu* p1 = new Stu('z', 'n', 20);
	delete p1;
}

在这里插入图片描述

我们会发现,new关键字在对自定义类型使用时,它会调用构造函数。delete在对自定义类型使用时,它会调用析构函数。

operator new 与 operator delete 函数

首先我们需要明白一点new和delete的底层调用逻辑是:
new —> operator new —> malloc —> 构造函数
delete —> 析构函数 + 释放空间 —> operator delete。

我们来用一个代码来证明:
在这里插入图片描述

new和delete是用户进行动态内存申请和释放的操作符,operator new和operator delete 是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。
我们来看源代码

/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否
则抛异常。
*/
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);
}
/*
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 );
	__FINALLY
	_munlock(_HEAP_LOCK); /* release other threads */
	__END_TRY_FINALLY
	return;
}
/*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)

通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续3申请,否则就抛异常。operator delete 最终是通过free来释放空间的。
这里需要注意:面向对象语言处理失败不喜欢用返回值,要建议用抛异常。

new和delete的实现原理

内置类型

如果申请的是内置类型的空间,new和malloc,delete和free基本类似不同的地方是:
new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而new在申请空间失败时会抛异常,malloc会返回NULL。

自定义类型

  • new的原理
    调用operator new函数申请空间
    在申请空间上执行构造函数,完成对象的构造
  • delete原理
    在空间上执行析构函数,完成对象中资源的清理工作
    调用operator delete函数释放对象的空间
  • new T[N]的原理
    调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
    在申请的空间上执行N次构造函数
  • delete[]的原理
    在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
    调用operator delete[]释放空间,实际在operator delete[] 中调用operator delete来释放空间。

定位new表达式

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。

//定位new表达式
class Stu
{
public:
	Stu(char name, char sex, int age)
	{
		cout << "Stu(char name, char sex, int age)" << endl;
		_name = name;
		_sex = sex;
		_age = age;
	}
	~Stu()
	{
		cout << "~Stu()" << endl;
	}
private:
	char _name;
	char _sex;
	int _age;

};
int main()
{
	Stu* p1 = (Stu*)malloc(sizeof(Stu));
	new(p1)Stu('y','n',20); //通过p1指针定位malloc出来的空间,
	//然后通过new来调用构造函数,对其空间进行赋值
	p1->~Stu();
	//这里的引用场景为:池化技术,可以提高效率,内存池,线程池,连接池。
	return 0;
}

好的,我们下一篇再见!

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

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

相关文章

使用强化学习破解迷宫实战

大家好&#xff0c;本文将实现一种强化学习算法来解决迷宫问题&#xff0c;并完成以下步骤&#xff1a;创建迷宫环境、定义迷宫类&#xff0c;以及使用值迭代算法&#xff08;Value Iteration algorithm&#xff09;找到穿越迷宫的最优策略。为了使这一过程可视化&#xff0c;使…

Stable Diffusion系列课程二:ControlNet

AUTOMATIC1111/stable-diffusion-webui参考B站Nenly视频《零基础学会Stable Diffusion》、视频课件推荐网站&#xff1a;stable-diffusion-art、Civitai&#xff08;魔法&#xff09; 、libilibi、AI艺术天堂推荐Stable Diffusion整合资料&#xff1a; NovelAI资源整合、《AI绘…

Flowable-网关-并行网关

目录 定义图形标记XML内容使用示例视频教程 定义 并行网关能在一个流程里用来对并发进行建模处理&#xff0c;它能把单条线路拆分成多个路径并行执 行&#xff0c;或者将多个路径合并处理。在一个流程模型里引入并发最直接的网关就是并行网关&#xff0c;它基于进 入和外出顺序…

回归预测 | MATLAB实现基于SVM-RFE-BP支持向量机递归特征消除特征选择算法结合BP神经网络的多输入单输出回归预测

回归预测 | MATLAB实现基于SVM-RFE-BP支持向量机递归特征消除特征选择算法结合BP神经网络的多输入单输出回归预测 目录 回归预测 | MATLAB实现基于SVM-RFE-BP支持向量机递归特征消除特征选择算法结合BP神经网络的多输入单输出回归预测预测效果基本介绍研究内容程序设计参考资料…

Android Studio中使用cmake开发JNI实战

JNI学习大纲 一、JNI编程入门 二、Android Studio中使用cmake开发JNI实战 第一章节我们介绍了JNI的开发步骤&#xff0c;那这一章节我们就开始在Android Studio中实战一下吧&#xff0c;Lets Start。 1. Android Studio中安装CMake插件 AS中菜单栏选择Tools>SDK Manager在…

Servlet是什么和创建、配置第一个servlet

Servlet是什么和创建、配置第一个servlet servlet是什么 2、创建servlet 方式一&#xff1a; 方式二&#xff1a; 方式三&#xff1a;

vscode中无法使用git解决方案

1 首先查看git安装目录 where git 2 找到bash.exe 的路径 比如&#xff1a;C:/Users/Wangzd/AppData/Local/Programs/Git/bin/bash 3 找到vscode的配置项setting.json 4 添加 "terminal.integrated.shell.windowns": "C:/Users/Wangzd/AppData/Local/Pr…

Python如何解决Amazon亚马逊“图文验证码”识别(6)

前言 本文是该专栏的第55篇,后面会持续分享python爬虫干货知识,记得关注。 在本专栏前面,笔者有详细介绍多种登录验证码识别方法,感兴趣的同学可往前翻阅。而本文,笔者将单独详细介绍亚马逊Amazon的图文识别验证码的解决方法。 如上图所示,访问或请求频次达到一定程度之…

IPv6地址分类,EUI-64转换规则

1、可聚合的单全球单播地址Global Unique Address&#xff1a; Aggregate global unicast address&#xff0c;前3位是001&#xff0c;即2000::/3&#xff0c;目前IANA已经将一部分可聚合全球单播进行了专门使用&#xff0c;如&#xff1a;2001::/16用于IPV6互联网&#xff0c;…

深挖 Threads App 帖子布局,我进一步加深了对CSS网格布局的理解

当我遇到一个新产品时&#xff0c;我首先想到的是他们如何实现CSS。当我遇到Meta的Threads时也不例外。我很快就探索了移动应用程序&#xff0c;并注意到我可以在网页上预览公共帖子。 这为我提供了一个深入挖掘的机会。我发现了一些有趣的发现&#xff0c;我将在本文中讨论。 …

Docker相关命令与入门

1. Docker 命令 # centos 7 systemctl start docker # 启动服务 systemctl stop docker systemctl restart docker # 重启服务 systemctl status docker systemctl enable docker # 开机自启动1.1 镜像相关的命令 # 查看镜像 docker images docker images -q # 查看…

深度学习:探究Tensor和Numpy

目录 引言 1 pytorch中Tensor 1.1 什么是Tensor 1.2 为什么需要Tensor 1.3 如何创建Tensor 1.3.1 从已有其他数据结构转化创建为Tensor 1.3.2 随机初始化一个Tensor 1.3.3 从已保存文件加载一个Tensor 1.4 Tensor的特性 1.4.1 丰富的常用函数操作 1.4.2 灵活的dtype和…

使用TensorBoard进行可视化

1. TensorBoard介绍 TensorBoard是TensorFlow推出的可视化工具&#xff0c;可以可视化模型结构、跟踪并以表格形式显示模型指标。 TensorBoard的使用包括两个步骤&#xff1a; 在代码中设置TensorBoard&#xff0c;在训练的过程中将会根据设置产生日志文件在浏览器中可视化该…

启动RocketMQ报错

说明&#xff1a;启动RocketMQ消费者时&#xff0c;报以下错误&#xff1a;java.lang.IllegalStateException&#xff1a;Failed to start RocketMQ push consumer. 解决&#xff1a;看下所有的监听器类&#xff0c;检查是不是有相同的消费者组名&#xff0c;注释掉其中一个即可…

文心一言 VS 讯飞星火 VS chatgpt (71)-- 算法导论7.1 1题

参照图 7-1的方法&#xff0c;说明 PARTITION在数组 A(13&#xff0c;19&#xff0c;9&#xff0c;5&#xff0c;12&#xff0c;8&#xff0c;7&#xff0c;4&#xff0c;21&#xff0c;2&#xff0c;6&#xff0c;11)上的操作过程。 文心一言&#xff1a; PARTITION 是一种常…

C++笔记之while循环的帧率监测与控制

C笔记之while循环的帧率监测与控制 code review! 文章目录 C笔记之while循环的帧率监测与控制1.两个时间相关的类2.例程3.运行4.代码 1.两个时间相关的类 2.例程 3.运行 4.代码 // 帧率监测与控制程序 #include <chrono> #include <iostream> #include <thre…

python 连接oracle pandas以简化excel的编写和数据操作

python代码 Author: liukai 2810248865qq.com Date: 2022-08-18 04:28:52 LastEditors: liukai 2810248865qq.com LastEditTime: 2023-07-06 22:12:56 FilePath: \PythonProject02\pandas以简化excel的编写和数据操作.py Description: 这是默认设置,请设置customMade, 打开koro…

Python爬虫的学习day02 requests 模块post 函数, lmxl 模块的 etree 模块

1. requests 模块post 函数 1.1 post 函数的参数 &#xff08;简单版&#xff09; 参数1&#xff1a; url 网络地址 参数2&#xff1a; data 请求数据 &#xff08;一般数据是 账号&#xff0c;密码&#xff09; 参数3&#xff1a; headers 头请求 &#xff08…

概念解析 | 虚拟镜面:超越三次反射的非视线成像

虚拟镜面:超越三次反射的非视线成像 注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:虚拟镜面在非视线成像中的应用。 参考文献:Royo D, Sultan T, Muoz A, et al. Virtual Mirrors: Non-Line-of-Sight Imaging Beyond the Th…

MyBatis关联查询

文章目录 前言多对一关联 association一对多关联 collection 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 关联查询是指在一个查询中同时获取多个表中的数据&#xff0c;将它们结合在一起进行展示。 关联表需要两个及以上的表 数据库代码&#xff1…