【C++】——内存管理(new和delete)

news2025/1/9 20:31:16

文章目录

  • 1. 前言
  • 2. C/C++内存分布
  • 3. C语言动态内存管理方式
  • 4. C++内存管理方式
    • 4.1 内置类型
    • 4.2 自定义类型
  • 5. operator new与operator delete函数
  • 6. new和delete的实现原理
  • 7. 定位new表达式(placement-new)
  • 8. 结尾

1. 前言

在学习C语言的时候,我们学习了动态内存管理,也就是在堆上动态开辟一些内存供我们使用,虽然C语言内存管理的方法在C++中也可以使用,但还有一些地方是他无能为力的,所以我们今天来学习C++内存管理的方式。

2. C/C++内存分布

在学习内存管理之前,我们先来认识一下C/C++中程序内存区域被划分为哪些。

1.栈又叫堆栈,存储非静态局部变量 / 函数参数 / 返回值等等,栈是向下增长的。
2.内存映射段是高效的I / O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。
3.堆用于程序运行时动态内存分配,堆是可以上增长的。
4.数据段,存储全局数据和静态数据。
5.代码段,存储可执行的代码 / 只读常量。

3. C语言动态内存管理方式

C语言中动态内存管理依靠的是4个函数:malloc、realloc、calloc、free
这些函数具体的功能可以看博主之前发布的C语言动态内存管理文章,有详细的讲解

void Test()
{
	int* p1 = (int*)malloc(sizeof(int));
	free(p1);
	int* p2 = (int*)calloc(4, sizeof(int));
	int* p3 = (int*)realloc(p2, sizeof(int) * 10);
	//这里不需要free(p2)
	free(p3);
}

int main()
{
	Test();
	return 0;
}

4. C++内存管理方式

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。

而new和delete对于内置类型和自定义类型有不同的处理方式,下面我们来学习new和delete分别对内置类型和自定义类型的处理方式。

4.1 内置类型

针对内置类型,new/delete跟malloc/free没有本质的区别,只有用法的区别,new/delete的用法简化了。

下面我们直接举例说明new和delete针对内置类型的用法。

void Test()
{
	//C语言
	//动态申请一个int类型的空间
	int* p1 = (int*)malloc(sizeof(int));

	//C++
	//动态申请一个int类型的空间
	int* p2 = new int;
	//申请5个int的数组
	int* p3 = new int[5];

	//申请1个int对象,初始化为5
	int* p4 = new int(5);

	//C++11支持new[] 用{}初始化  C++98不支持
	int* p5 = new int[5]{1,2,3};

	//C语言
	free(p1);

	//C++
	delete p2;
	delete[] p3;
	delete p4;
	delete[] p5;
}

int main()
{
	Test();
	return 0;
}

注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],一定要匹配起来使用。

4.2 自定义类型

在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与free不会。

例如:

class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "A():" << this << endl;
	}

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

private:
	int _a;
};


int main()
{
	//C语言
	//malloc
	//在堆上申请空间
	A* p1 = (A*)malloc(sizeof(A));
	if (p1 == NULL)
	{
		perror("malloc fail\n");
		return 0;
	}

	//释放空间
	free(p1);

	//C++
	//new
	//在堆上申请空间、调用构造函数初始化
	//A* p2 = new A;
	A* p3 = new A(10);

	//调用析构函数清理对象中的资源、释放空间
	delete p3;

	return 0;
}

在这里插入图片描述

总结:new/delete和malloc/free最大区别是new/delete对于自定义类型除了开辟空间还会调用构造函数和析构函数,对于内置类型这两者几乎是一样的。

5. operator new与operator delete函数

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

operator new:
该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回,申请空间失败时,就尝试执行空间不足的应对措施,如果该应对措施用户已经设置了,就继续申请,否则抛异常。

operator delete:
该函数最终是通过free来释放空间的。

6. new和delete的实现原理

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

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

7. 定位new表达式(placement-new)

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
使用格式
new (place_address) type或者new (place_address) type(initializer - list)
place_address必须是一个指针,initializer - list是类型的初始化列表
使用场景
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。

class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << "A():" << this << endl;
	}

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

private:
	int _a;
};

int main()
{
	A* p1 = new A;

	A* p2 = (A*)malloc(sizeof(A));
	if (p2 == nullptr)
	{
		perror("malloc fail");
		return 0;
	}

	//new(p2)A;
	new(p2)A(10);

	return 0;
}

8. 结尾

C++内存管理的方式我们就学习到这里,在学习了new和delete之后,我们以后还是尽量使用new和delete,因为new和delete比起malloc和free不仅简洁了很多,而且还更加实用和智能了。
最后,感谢各位大佬的耐心阅读和支持,觉得本篇文章写的不错的朋友可以三连关注支持一波,如果有什么问题或者本文有错误的地方大家可以私信我,也可以在评论区留言讨论,再次感谢各位。

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

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

相关文章

物联网协议之MQTT

MQTT 简介 MQTT 可以简单看做一个网络协议&#xff0c;用于机器对机器的通信&#xff08;与客户端到服务器的传输有点区别&#xff09;。智能传感器、可穿戴设备和其他物联网&#xff08;IoT&#xff09;设备通常必须通过带宽有限的资源受限网络传输和接收数据。这些物联网设…

更新cuda和 pytorch==1.12.1版本,更新到cuda11.3.1

nvidia-smi 查看gpu支持的最高cuda版本 nvcc -V 查看当前cuda版本 卸载旧版本cuda 除了NVIDIA Geforce、NVIDIA PhysX、NVIDIA图形驱动程序&#xff0c;将电脑中其他NVIDIA开头的全部卸载 安装cuda 下载适合的cuda版本 https://developer.nvidia.com/cuda-toolkit-ar…

基于QT开发的使用OPC_UA与西门子1200,1500系列PLC通信的工业监控Demo

目录 一&#xff0c;总体介绍 二&#xff0c;需要的软件 三&#xff0c;需要的硬件 四&#xff0c;QT程序代码 五&#xff0c;西门子PLC代码 一&#xff0c;总体介绍 先看一下图1-1的QT运行界面图&#xff0c;界面中服务器地址就是OPC_UA服务器地址&#xff0c;整个项目作…

图解LeetCode——19. 删除链表的倒数第 N 个结点

一、题目 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 二、示例 2.1> 示例 1&#xff1a; 【输入】head [1,2,3,4,5], n 2 【输出】[1,2,3,5] 2.2> 示例 2&#xff1a; 【输入】head [1], n 1 【输出】[] 2.3> 示例…

数值计算 - 误差的来源

误差的来源是多方面的&#xff0c;但主要来源为&#xff1a;过失误差&#xff0c;描述误差&#xff0c;观测误差&#xff0c;截断误差和舍入误差。 过失误差 过失误差是由设备故障和人为的错误所产生的误差&#xff0c;在由于每个人都有“权利”利用机器进行数值计算,所以在计算…

#include <archive.h>报错

#include <archive.h>报错 archive配置 Linux环境下&#xff0c;在C项目.cpp文件中存在如下语句&#xff0c;导致无法运行~ #include <archive.h> #include <archive_entry.h>由于C编译器默认不包含archive&#xff0c;所以我们需要自行配置。 Libarchiv…

Java 基础--interview经典(个人认为)题目

1&#xff09;多线程中 synchronized 锁升级的原理是什么&#xff1f; synchronized 锁升级原理&#xff1a;在锁对象的对象头里面有一个 threadid 字段&#xff0c;在第一次访问的时候 threadid 为空&#xff0c;jvm 让其持有偏向锁&#xff0c;并将 threadid 设置为其线程 i…

终の序章(一)

前言 写在我大三的最后一次省赛 &#xff0c;也是最后一次比赛 从半年前区域赛的大失利&#xff0c;导致我曾一度放弃算法竞赛和算法训练 新路历程 考虑到前几次的省赛&#xff0c;我们这次采取 稳 的一种方式&#xff0c;因为前几次省赛难度跨度较 大&#xff0c;对于大部…

【牛客网面试必刷TOP101】链表篇(二)

【牛客网面试必刷TOP101】链表篇&#xff08;二&#xff09; 前言刷题网站刷题&#xff01;BM4 合并两个排序的链表思路一&#xff1a;双指针思路二&#xff1a;递归&#xff08;扩展思路&#xff09; BM5 合并k个已排序的链表思路一&#xff1a;归并排序思想 BM6 判断链表中是…

内网渗透(七十九)之 CVE-2021-42287 权限提升漏洞

CVE-2021-42287 权限提升漏洞 漏洞背景 2021年11月9日,微软发布11月份安全补丁更新。在该安全补丁更新中,修复了两个域内权限提升漏洞CVE-2021-42287 、CVE-2021-42278。当时这两个漏洞的利用详情和POC并未公布,因此并未受到太多人关注。 一个月后,国外安全研究员公布了…

[CTF/网络安全] 攻防世界 ics-06 解题详析

[CTF/网络安全] 攻防世界 ics-06 解题详析 姿势&#xff08;Burp爆破&#xff09; 题目描述&#xff1a;云平台报表中心收集了设备管理基础服务的数据&#xff0c;但是数据被删除了&#xff0c;只有一处留下了入侵者的痕迹。 可知&#xff1a;报表中心含有部分数据 仅报表中心…

C++内存管理/函数模板/类模板

一、C内存管理 C中内存基本形式与C语言类似&#xff0c;可以参考下图。 X64环境下总共大小为8G,X86环境下为4G。 1、内核空间&#xff1a;用户不能读写&#xff0c;但要占用一定空间。 2、栈区&#xff1a;以开辟、销毁栈帧形式运行&#xff0c;主要应用于局部变量和函数栈帧…

chatgpt赋能Python-python3_choice

Python3中的choice()函数&#xff1a;一种简单而有趣的随机选择方式 在Python3中&#xff0c;choice()函数是一个常见的随机模块。它允许我们从一个序列中随机选择一个元素。这在程序中经常用于生成一些需要随机展示的数据。本文将介绍Python3中的choice()函数&#xff0c;并探…

00.SpringCloud服务调用方式

服务调用方式 RPC和HTTP 无论是微服务还是SOA&#xff0c;都面临着服务间的远程调用。那么服务间的远程调用方式有哪些呢&#xff1f; 常见的远程调用方式有以下2种&#xff1a; RPC&#xff1a;Remote Produce Call远程过程调用&#xff0c;类似的还有 。自定义数据格式&am…

合合信息亮相CCIG2023:多位大咖共话智能文档未来,文档图像内容安全还面临哪些技术难题?

近日&#xff0c;中国图象图形大会&#xff08;CCIG 2023&#xff09;&#xff08;简称“大会”&#xff09;在苏州圆满落幕。本届大会以“图象图形向未来”为主题&#xff0c;由中国科学技术协会指导&#xff0c;中国图象图形学学会主办&#xff0c;苏州科技大学承办&#xff…

干货 | 利用SPSS进行高级统计第一期(更新)

Hello&#xff0c;大家好&#xff01; 这里是壹脑云科研圈&#xff0c;我是喵君姐姐~ 在之前的文章中&#xff0c;我们以此介绍了如何利用SPSS进行高级统计分析&#xff0c;内容包括&#xff1a; (1)描述性统计表格模板、卡方&T检验、相关&回归分析 (2)中介、多重中…

MD5_buuctf

概念 MD5信息摘要算法&#xff0c;一种被广泛使用的密码散列函数&#xff0c;可以产生出一个128位&#xff08;16字节&#xff09;的散列值&#xff08;hash value&#xff09;&#xff0c;用于确保信息传输完整一致。 MD5算法具有以下特点&#xff1a; 压缩性&#xff1a;任意…

一次失败的面试经历:我只想找个工作,你却看不起我?还用面试题羞辱我...

这段时间都说难找工作&#xff0c;没有面试机会。面对如此严峻的形式&#xff0c;很多软件测试人员都希望能拿一个满意的高薪offer&#xff0c;但是随着招聘职位的不断增多&#xff0c;面试的难度也随之加大&#xff0c;而面试官更是会择优录取 我最近为面试已经焦头烂额了&am…

循坏队列+OJ题之设计循环队列

生命不是要等待风暴过去&#xff0c;而是要学会在风暴中跳舞。 ——卡莉尔吉布朗目录 &#x1f33a;前言&#xff1a; &#x1f341;一.循环队列是什么&#xff1f; &#x1f34f;二.循环队列有什么作用&#xff1f; &#x1f340;三.OJ题之设计循环队列 1…

C++(3):字符串、向量和数组

命名空间的 using 声明 using namespace::name;1.每个名字都需要独立的 using 声明&#xff1b; 2.头文件不应包含 using 声明&#xff1a; 因为头文件的内容会拷贝到所有引用它的文件中去&#xff0c;如果头文件里有某个using声明&#xff0c;那么每个使用了该头文件的文件就…