C++中的内存管理

✨前言✨

📘 博客主页:to Keep博客主页
🙆欢迎关注,👍点赞,📝留言评论
⏳首发时间:2023年11月21日
📨 博主码云地址:博主码云地址
📕参考书籍:《C++ Primer》《C++编程规范》
📢编程练习:牛客网+力扣网
由于博主目前也是处于一个学习的状态,如有讲的不对的地方,请一定联系我予以改正!!!

C++内存管理

  • 1 C++内存分布
  • 2 C++内存管理方式
    • 2.1 处理内置类型
    • 2.2 处理自定义类型
  • 3 operator new与operator delete函数
  • 4 定位new表达式
  • 5 malloc/free和new/delete的区别

1 C++内存分布

在这里插入图片描述
C++根据不同的数据需求有着不同的存储特性,所以将内存分为多个区域来存储数据!

2 C++内存管理方式

在C语言中,我们是利用malloc/calloc/relloc进行动态内存管理!其中relloc就是对之前malloc申请的空间进行扩展,calloc就是malloc加上memset(),而C++是通过new和delete操作符进行动态内存管理

2.1 处理内置类型

利用new和delete操作符进行动态内存管理比C语言中的malloc方便好写了许多!

int main()
{
	int* b1 = new int;    //申请一个int的空间
	int* b2 = new int[5]; //利用new[]操作符,申请5个连续int的空间,就是一个数组
	delete b1;
	delete[] b2;
	return 0;
}

通过调试,我们可以进一步的了解new和delete操作符是如何处理内置类型的!
在这里插入图片描述
可以发现,new其实和C语言中的malloc是一样的,也是不会进行初始化的,只是动态开辟空间!相比较于malloc而言,new是不用进行强制类型转换,也不用自己去计算要开辟空间的大小了!同理,delete就相当于free,释放对应开辟的空间!

注意:new和delete要搭配使用,new[]和delete[]搭配使用!不要混着使用,否则会出现内存泄露或者程序不能正常运行的问题!

利用new其实也是可以对内置类型进行初始化的!代码如下:

int main()
{
	int* p1 = new int(10); //开辟一个int空间,结合()中的内容进行初始化
	int* p2 = new int[5] {1, 2, 3}; //开辟5个连续的int空间,结合{}中的内容进行初始化

	delete p1;
	delete[] p2;
	return 0;
}

调试结果如图所示:
在这里插入图片描述
可以发现对于5个连续的int空间,只要我们给定一些空间的初始化,后面的空间编译器就把它初始化成为0的!

2.2 处理自定义类型

对于自定义类型如果使用malloc,我们就无法对自定义类型进行初始化!因为构造函数不可以通过所给的对象指针直接调用:
在这里插入图片描述
利用new和delete操作符如何处理自定义类型呢?我们可以参考如下代码进行理解:

class Date {
private:
	int _year;
	int _month;
	int _day;

public:
	Date(int year = 2023 , int month = 11, int day = 21)
	{
		cout << "Date 构造函数调用了" << endl;
		_year = year;
		_month = month;
		_day = day;
	}

	~Date(){
		cout << "析构函数被调用了" << endl;
	}
};

int main()
{
	Date* d1 = new Date(2023,11,21);
	Date* d2 = new Date[5]{ Date(2023,11,20) };//初始化一部分,其他的是默认构造初始化,如果没有默认构造也会报错
	Date* d3 = new Date;//调用默认构造,无默认构造就会报错

	delete d1;
	delete[] d2;
	delete d3;
	return 0;
}

运行结果如下:
在这里插入图片描述

从以上我们就可以知道new和delete处理自定义类型的原理

new就是开辟对象空间+调用构造函数,malloc就不会调用构造函数
delete就是调用析构函数+释放对象空间,free就不会调用析构函数

3 operator new与operator delete函数

operator new和operator delete是系统提供的全局函数!我们先来看这样一段代码:

class Stack {
private:
	int* p;
	int _capacity;
	int _top;

public:
	Stack(int capacity = 4)
	{
		cout << "Stack(int capacity = 4)" << endl;
		p = new int[capacity];
		_capacity = capacity;
		_top = 0;
	}

	~Stack()
	{
		cout << "~Stack()" << endl;
		delete[] p;
		_capacity = _top = 0;
		p = nullptr;
	}

};
int main()
{
	Stack st1;
	Stack* st2 = new Stack;
	return 0;
}

如何理解上述的两个new呢?如图所示:
在这里插入图片描述
第一个new是开辟对象的空间,第二个new是开辟对象中p所指的空间!这也就和之前的知识点联系上了,利用delete就是先调用析构,清理对象中的额外资源也就是动态开辟所需的空间!在释放对象的空间!通过这个例子,我们可以更深刻的理解new和delete的工作原理!那么new和delete底层是怎样实现的呢?
运行以下这段代码:

int main()
{
	Stack* st1 = new Stack;
	Stack* st2 = (Stack*)operator new(sizeof(Stack));
	return 0;
}

调试与运行结果如图:
在这里插入图片描述

在这里插入图片描述
我们可以发现通过operator new函数和malloc一样,只是开辟了空间,并不会调用构造函数进行初始化!实际上operator new底层封装的就是malloc!那为什么不直接用malloc呢?那是因为我们要面向对象编程,malloc返回值是0,我们通过operator new是可以抛异常的!更加符合面向对象编程!而operator delete也同理,是封装了free!简单来说既可以用下图来概括!
在这里插入图片描述
在这里插入图片描述

4 定位new表达式

可以通过定位new显式的调用构造函数!在实际应用中,定位new一般是配合内存池使用的,因为内存池分配出来的空间没有初始化,因此如果需要在这块内存池分配出来的空间上构造自定义类型的对象,需要使用定位new显式调用构造函数构造目标对象

格式如下:
new(申请对象地址)类型
new(申请对象地址)类型(类型的初始化列表)

例子如下:

//定位new的使用

class A {
private:
	int _a;
	int _b;

public:

	A(int a = 10)
	{
		cout <<"A(int a = 10)"<< endl;
		_a = a;
	}

	A(int a , int b )
	{
		cout << "A(int a = 1, int b = 2)" << endl;
	}

	~A()
	{
		cout << "~A()" << endl;
	}
};

int main()
{
	A* a1 = (A*)operator new(sizeof(A));//开辟对象的空间
	new(a1)A;//定位new,显式的调用构造函数,调用默认构造
	a1->~A();//显式的调用析构函数
	free(a1);//释放对象空间

	A* a2 = (A*)operator new(sizeof(A));
	new(a2)A(10, 20);//定位new,调用两个参数的构造函数
	a2->~A();
	free(a2);
}

显式调用了构造函数,那就要显式调用析构函数,要配对使用就可以了!

5 malloc/free和new/delete的区别

相同点:都是从堆上开辟空间,都需要手动的进行释放!
不同之处在于:
1️⃣malloc和free是函数,而new和delete是操作符。
2️⃣malloc不会进行初始化,new开辟空间的同时可以初始化。
3️⃣malloc开辟失败是返回NULL需要我们进行判断,new开辟失败是抛出异常。
4️⃣malloc开辟空间需要手动计算大小并进行传递,而new就可以不用去计算大小!
5️⃣对于自定义类型,malloc不会去调用构造函数,free不会去调用析构函数!而new会去调用构造函数进行初始化,delete会去调用析构函数进行清理!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何选择适合的开源框架来构建微服务架构?

随着科技的飞速发展&#xff0c;云计算和大规模应用的需求日益显著&#xff0c;这促使微服务架构在软件开发领域中占据了主流地位。微服务架构的广泛应用为开发人员提供了灵活性、可伸缩性和高可用性&#xff0c;从而推动了快速的应用程序开发。然而&#xff0c;在构建微服务架…

ky10 server x86 安装、更新openssl3.1.4(在线编译安装、离线安装)

查看openssl版本 openssl version 离线编译安装升级 #!/bin/shOPENSSLVER3.1.4OPENSSL_Vopenssl versionecho "当前OpenSSL 版本 ${OPENSSL_V}" #------------------------------------------------ #wget https://www.openssl.org/source/openssl-3.1.4.tar.gzech…

git撤销某一次commit提交

一&#xff1a;撤销上一次commit提交&#xff0c;但不删除修改的代码 可以使用使用VSCode 二&#xff1a;使用 git reset --hard命令删除提交时&#xff0c;将会删除该提交及其之后的所有更改&#xff08;相当于你想要回滚到的提交的提交ID&#xff09; git reset --hard 版本…

ubuntu18.04安装并运行ORB-SLAM2

查看版本号 lsb_release -a 换源 Ubuntu系统自带的源都是国外的网址&#xff0c;国内用户在使用的时候下载比较慢甚至无法获取&#xff0c;需要替换成国内的镜像源 备份源文件 sudo cp /etc/apt/sources.list /etc/apt/sources.list.old 打开文件 sudo gedit /etc/apt/so…

【Python】153是一个非常特殊的数,它等于它的每位数字的立方和,即153=1*1*1+5*5*5+3*3*3。编程求所有满足这种条件的三位十进制数。

问题描述 153是一个非常特殊的数&#xff0c;它等于它的每位数字的立方和&#xff0c;即1531*1*15*5*53*3*3。编程求所有满足这种条件的三位十进制数。 输出格式 按从小到大的顺序输出满足条件的三位十进制数&#xff0c;每个数占一行。 方法一&#xff1a; for i in range(10…

入行IC | 从小白助理级,到总监专家级,到底要经历怎样的成长阶段呢?

《中国集成电路产业人才发展报告》是业内和IC设计、IC人才都息息相关的一份报告。 &#xff08;文末可领全部报告资料&#xff09; * 从报告数据来看&#xff0c;无论在半导体产业的哪个环节&#xff0c;个人发展路径和年薪待遇都是逐级攀升的趋势。 那么从小白助理级&a…

k8s-pod管理 3

pod是可以创建和管理k8s 计算的最小可部署单元&#xff0c;一个pod 代表着集群中运行的一个进程&#xff0c;每个pod 都有一个唯一的ip pod包裹了容器 下载测试镜像 创建自主式的pod 查看创建的pod的详情信息 删除pod 创建控制器 副本过多&#xff0c;需要进行负载均衡减轻节点…

外部 prometheus监控k8s集群资源

prometheus监控k8s集群资源 一&#xff0c;通过CADvisior 监控pod的资源状态1.1 授权外边用户可以访问prometheus接口。1.2 获取token保存1.3 配置prometheus.yml 启动并查看状态1.4 Grafana 导入仪表盘 二&#xff0c;通过kube-state-metrics 监控k8s资源状态2.1 部署 kube-st…

【操作系统】文件系统的实现

文章目录 文件系统的层次结构文件系统的实现目录实现线性列表哈希表 文件的实现连续分配链接分配索引分配 文件存储空间管理空闲表法与空闲链表法成组链接法位示图法 文件系统的层次结构 文件系统从上往下分为了五层&#xff0c;分别是用户调用接口、文件目录系统、存取控制模…

解放双手!一键助你快速发圈、批量加好友,好用哭了!

朋友们&#xff0c;你们有没有经历过管理多个微信账号的繁琐和压力&#xff1f; 会不会因为忙不过来&#xff0c;忘记及时回复客户&#xff0c;错过了推广的时机&#xff1f; 别担心&#xff0c;现在有了微信管理系统&#xff0c;一切都变得简单轻松起来&#xff01; 微信管…

打造高效医患沟通:陪诊小程序开发技术指南

随着科技的不断发展&#xff0c;陪诊小程序作为医患沟通的新工具逐渐成为关注焦点。本文将带领你通过使用React和Node.js技术栈&#xff0c;构建一个功能强大且用户友好的陪诊小程序&#xff0c;实现医患互动的便捷和高效。 1. 准备工作 确保你的开发环境中已安装了Node.js和…

Unity下载资源且保存

UnityWebRequest(WWW——已过时) 替代&#xff1a;Unity不再支持WWW后&#xff0c;使用UnityWebRequest完成web请求。 Unity - Scripting API: UnityWebRequest (unity3d.com)https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequest.html if (www.isNetworkEr…

Java 多线程之 volatile(可见性/重排序)

文章目录 一、概述二、使用方法三、测试程序3.1 验证可见性的示例3.2 验证指令重排序的示例 一、概述 在Java中&#xff0c;volatile 关键字用于修饰变量&#xff0c;其作用是确保多个线程之间对该变量的可见性和禁止指令重排序优化。 当一个变量被声明为volatile时&#xff0…

基于Vue+SpringBoot的校园电商物流云平台开源项目

项目编号&#xff1a; S 034 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S034&#xff0c;文末获取源码。} 项目编号&#xff1a;S034&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 商品数据模块2.3 快…

企业怎么进行人事管理?一篇文章带你了解!

阅读本文你将了解企业如何运用数字化工具进行人事管理&#xff1a;一、数字化、线上化&#xff0c;解放人力&#xff1b;二、规范管理流程&#xff0c;提升处理效率&#xff1b;三、数据分析可视化&#xff0c;支持并优化决策&#xff1b;四、个性化定制&#xff0c;灵活适应需…

mac 和 windows 相互传输文件【共享文件夹】

文章目录 前言创建共享文件夹mac 连接共享文件夹 前言 温馨提示&#xff1a;mac 电脑和 windows 电脑必须处于同一局域网下 本文根据创建共享文件夹的方式实现文件互相传输&#xff0c;所以两台电脑必须处于同一网络 windows 创建共享文件夹&#xff0c;mac 电脑通过 windows…

Enterprise Architect安装与使用

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl Enterprise Architect概述 官方网站&#xff1a;https://www.sparxsystems.cn/products/ea/&#xff1b;图示如下&#xff1a; Enterprise Architect是一个全功能的、基于…

Spring-IOC-FactoryBean机制(难点且重点)

1、第一个案例 1.1、Book.java package com.atguigu.ioc; import lombok.Data; Data public class Book {private String bid;private String bname; }1.2、Book2.java package com.atguigu.ioc; import lombok.Data; Data public class Book2 extends Book {private String co…

SocketIo的使用和基于SocketIO的聊天室

Socket.IO 是一个库&#xff0c;可以在客户端和服务器之间实现 低延迟, 双向 和 基于事件的 通信。 一、Socket.IO的特点 以下是 Socket.IO 在普通 WebSockets 上提供的功能&#xff1a; 1、HTTP 长轮询回退 如果无法建立 WebSocket 连接&#xff0c;连接将回退到 HTTP 长轮…

文化传承与数字技术的完美结合:十八数藏的新纪元

在这数字化的时代&#xff0c;十八数藏犹如一座连接过去与未来的桥梁&#xff0c;展现出文化传承与数字技术完美结合的新纪元。十八数藏以其独特的视角&#xff0c;将传统文化注入现代数字技术的脉络&#xff0c;呈现出一幅文化传承的全新画卷。 十八数藏的文化传承并不是简单的…