C++基础语法——内存管理

news2024/11/18 7:48:57

1. C/C++中的内存管理

我们先看如下一段代码

#include <iostream>

using namespace std;

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);
}

 在C/C++中,各数据的分布如下

注:

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

2. C/C++中的动态内存管理

①C语言的动态内存管理

详情可以查看:

动态内存管理(C语言)

②C++的动态内存管理

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

Ⅰ. 操作内置类型

void Test()
{
	// 动态申请一个int类型的空间
	int* ptr4 = new int;

	// 动态申请一个int类型的空间并初始化为10
	int* ptr5 = new int(10);

	// 动态申请10个int类型的空间
	int* ptr6 = new int[3];

    // 释放单个元素直接delete
	delete ptr4;
	delete ptr5;

    // 释放数组使用delete[]
	delete[] ptr6;
}

Ⅱ. 操作自定义类型

对于下列代码

class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << "A():" << this << endl;
	}
	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
};
int main()
{
	// new/delete 和 malloc/free最大区别是 
	// new/delete对于[自定义类型]除了开空间还会调用构造函数和析构函数
	A* p1 = (A*)malloc(sizeof(A));
	A* p2 = new A(1);

	free(p1);
	delete p2;

	cout << "--------------------------" << endl;

	// 内置类型是几乎是一样的
	int* p3 = (int*)malloc(sizeof(int)); // C
	int* p4 = new int;

	free(p3);
	delete p4;

	A* p5 = (A*)malloc(sizeof(A) * 10);
	A* p6 = new A[10];
	free(p5);
	delete[] p6;
	return 0;
}

 运行后,我们发现有

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

free不会

3. operator new与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;
}

观察上面的代码之后,我们可以知道本质上来说 operator new == malloc 其不同之处在于operator new失败时,返回抛异常,而malloc失败时,返回空指针,类似地 operator delete == free

4. new与delete的实现原理

Ⅰ. 操作内置类型

操作内置类型时,new和delete调用operator new和operator delete函数,与malloc和free并无太大差异。

Ⅱ. 操作自定义类型

而在处理自定义类型时,new会先调用operator new函数再调用自定义类型的构造函数,而delete会先调用析构函数再调用operator delete函数。

new

delete

为什么要如此设计呢,我们举一个具体例子来说,比如我们要在堆上申请一个栈对象

int main()
{

	Stack* st = new Stack;
	delete st;
	return 0;
}

 有

5. 定位new的表达式

定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象
通俗来说,就是使用new的定义表达式进行显示调构造函数进行初始化。
class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << "A():" << this << endl;
	}
	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
};

// 定位new/replacement new
int main()
{
	// p1现在指向的只不过是与A对象相同大小的一段空间,还不能算是一个对象,因为构造函数没有执行
	A* p1 = (A*)malloc(sizeof(A));
	new(p1)A;  // 注意:如果A类的构造函数有参数时,此处需要传参
	p1->~A();
	free(p1);

	A* p2 = (A*)operator new(sizeof(A));
	new(p2)A(10);
	p2->~A();
	operator delete(p2);
	return 0;
}

6. 相关常见面试题

malloc/freenew/delete的区别

共同点:
都是从堆上申请空间,并且需要用户手动释放。
不同点:
1. malloc free 是函数, new delete 是操作符
2. malloc 申请的空间不会初始化, new 可以初始化
3. malloc 申请空间时,需要手动计算空间大小并传递, new 只需在其后跟上空间的类型即可,如果是多个对象,[] 中指定对象个数即可
4. malloc 的返回值为 void*, 在使用时必须强转, new 不需要,因为 new 后跟的是空间的类型
5. malloc 申请空间失败时,返回的是 NULL ,因此使用时必须判空, new 不需要,但是 new
要捕获异常
6. 申请自定义类型对象时, malloc/free 只会开辟空间,不会调用构造函数与析构函数,而 new在申请空间后会调用构造函数完成对象的初始化,delete 在释放空间前会调用析构函数完成空间中资源的清理

什么是内存泄漏,内存泄漏的危害 

什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。

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

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

相关文章

rk3399 buildroot ubuntu20版本编译遇到问题

一、编译uboot遇到问题 /usr/include/libfdt.h:258:1: error: redefinition of fdt_set_version 258 | fdt_set_hdr_(version); | ^~~~~~~~~~~~ In file included from tools/fdt_host.h:11, from tools/imagetool.h:22, from tools…

BurpSuite—-Target模块(目标模块)

前言 本文主要介绍BurpSuite—-Target模块(目标模块)的相关内容 关于BurpSuite的安装可以看一下之前这篇文章&#xff1a; http://t.csdn.cn/cavWt Target功能 目标工具包含了SiteMap&#xff0c;用你的目标应用程序的详细信息。它可以让你定义哪些对象在范围上为你目前的工…

基于QGIS的长株潭城市群边界范围融合实战

背景 在面向区域的研究过程中&#xff0c;比如一些研究区域&#xff0c;如果是具体的行政区划&#xff0c;比如具体的某省或者某市或者县&#xff0c;可以直接从国家官方的地理数据中直接下载就可以。但如果并没有直接的空间数据那怎么办呢&#xff1f;比如之前遇到的一个场景&…

chatgpt赋能Python-python3_len__

Python3 len()函数&#xff1a;使用方法和常见应用 在Python中&#xff0c;len()函数是一个内置函数&#xff0c;用于返回对象的长度或元素的个数。它适用于字符串、列表、元组、字典、集合等Python数据类型。在本篇文章中&#xff0c;我们将深入探讨Python3 len()函数的使用方…

C++ [STL之string模拟实现]

本文已收录至《C语言和高级数据结构》专栏&#xff01; 作者&#xff1a;ARMCSKGT STL之string模拟实现 前言正文存储结构默认成员函数构造函数析构函数拷贝构造函数赋值重载 容量操作类获取字符串长度size获取当前容量capacity查询是否为空串emptyreserve扩容调整字符串大小si…

基于Freertos的ESP-IDF开发——6.使用DHT1温湿度传感器

基于Freertos的ESP-IDF开发——6.使用DHT1温湿度传感器 0. 前言1. DHT11驱动原理2. 完整代码3. 演示效果4. 其他FreeRtos文章 0. 前言 开发环境&#xff1a;ESP-IDF 4.3 操作系统&#xff1a;Windows10 专业版 开发板&#xff1a;自制的ESP32-WROOM-32E 准备一个DHT11温湿度传…

【Element-ui】el-table大数据量渲染卡顿问题

1、场景描述 在项目开发中&#xff0c;遇到在表格中一次性加载完的需求&#xff0c;且加载数量不少&#xff0c;有几百几千条&#xff0c;并且每条都可能有自己的下拉框&#xff0c;输入框来做编辑功能&#xff0c;此时普通的el-table肯定会导致浏览器卡死&#xff0c;那么怎么…

Windows10 双网卡配置,轻松实现内外互通

1 背景 我平常需要连接外网查阅资料&#xff0c;聊天等&#xff0c;做实验时需要将写到的代码打包部署到内网服务器中&#xff0c;所以需要频繁地切换内外网&#xff0c;修改静态网络配置。很是苦恼。 2 方法 最近&#xff0c;我找到了几种解决办法。 方法一、…

uniapp DIY可视化工具 控件拖拽工具怎么开发/拖拽库/模板引擎

uniapp DIY可视化工具 控件拖拽工具怎么开发 答&#xff1a;需要 (**拖拽库**) &#xff08;**模板引擎**&#xff09;代码自动生成 python有哪些模板引擎 Jinja2是一个小型但快速且易于使用的以纯python编写的独立模板引擎&#xff08;最主要的模板&#xff09;Chameleon是T…

深度学习之卷积神经网络(CNN)

大家好&#xff0c;我是带我去滑雪&#xff01; 卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;是一种基于深度学习的前馈神经网络&#xff0c;主要用于图像和视频识别、分类、分割和标注等计算机视觉任务。它主要由卷积层、池化层、全连接…

【开源、应用】QT—TCP网络上位机的设计

本文设计一个终端控制的上位机软件&#xff08;如“设计目标”下图所示&#xff09;&#xff0c;可以和STM32、Adruino等通信实现无线局域网控制系统。 本文的通信内容和图表内容可以参考作者之前的文章 STM32ESP8266连接电脑Qt网络上位机——QT篇https://blog.csdn.net/qq_53…

【STM32G431RBTx】备战蓝桥杯嵌入式→决赛试题→第六届

文章目录 前言一、题目二、模块初始化三、代码实现interrupt.h:interrupt.c:main.h:main.c: 四、完成效果五、总结 前言 无 一、题目 二、模块初始化 1.LCD这里不用配置&#xff0c;直接使用提供的资源包就行 2.ADC:开启ADCsingle-ended 3.LED:开启PC8-15,PD2输出模式就行了…

【JVM001】宋红康JVM字节码举例

宋红康JVM字节码举例 1 Integer package jvmT; public class IntegerTest {public static void main(String[] args) {Integer i 5;int y 5;System.out.println(iy); //trueInteger i6 5;Integer y6 5;System.out.println(i6y6);//trueInteger i5 128;Integer y5 128;System.…

SpringBoot中使用lombok

1.添加依赖 在项目的根目录中找到pom.xml&#xff0c;在dependencies下复制这段代码 <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifac…

解决Python爬虫中selenium模块中的find_element_by_id方法无法使用

如有错误&#xff0c;敬请谅解&#xff01; 此文章仅为本人学习笔记&#xff0c;仅供参考&#xff0c;如有冒犯&#xff0c;请联系作者删除&#xff01;&#xff01; 我们在学习selenium模块的时候&#xff0c;经常会用到 browser.find_element_by_id命令&#xff0c;但随着se…

代码随想录算法训练营第四十六天 | bool的背包题,细节多

139.单词拆分 文档讲解&#xff1a;代码随想录 (programmercarl.com) 视频讲解&#xff1a;动态规划之完全背包&#xff0c;你的背包如何装满&#xff1f;| LeetCode&#xff1a;139.单词拆分_哔哩哔哩_bilibili 状态&#xff1a;不会做&#xff0c;不知道怎么把bool类型与背包…

推荐系统系列之推荐系统概览(下)

在推荐系统概览的第一讲中&#xff0c;我们介绍了推荐系统的常见概念&#xff0c;常用的评价指标以及首页推荐场景的通用召回策略。本文我们将继续介绍推荐系统概览的其余内容&#xff0c;包括详情页推荐场景中的通用召回策略&#xff0c;排序阶段常用的排序模型&#xff0c;推…

软件测试实验:loadrunner的高级使用

目录 前言实验目的实验内容实验要求实验过程loadrunner中插入事务与集合点loadrunner中插入检查点loadrunner中参数化-table分析报告功能loadrunner手动设置场景loadrunner监视图标 总结 前言 本实验主要介绍了loadrunner这一强大的性能测试工具的高级使用方法&#xff0c;包括…

python实现九宫格的车辆路径轨迹上位机界面

实验环境&#xff1a;wxFormBuilder v3.5 python3.7.5 MC9S12G128开发板 基本功能&#xff1a;控制开发板上的按键&#xff0c;模拟车辆移动的上下左右四个方位&#xff0c;通过can通信告诉上位机界面&#xff0c;车辆轨迹的移动方位&#xff1b; 1. python重新封装control…

技巧:jetbrain全家桶系列如何撤销已经提交本地仓库但还没push的commit

目录 1. 哎呀&#xff0c;不小心把不能提交的“机密”加入commit了2. 使用reset来修复的话要注意有坑&#xff0c;选Soft和Mixed&#xff0c;千万别选Hard和Keep3. 使用revert&#xff0c;只能修修补补&#xff0c;但commit还在&#xff0c;当然有好处是会留下使用痕迹&#xf…