CC++内存管理方式

news2024/11/24 2:59:03

文章目录

  • 1. C/C++内存分布
    • 总结
  • C语言中动态内存管理
  • C++内存管理方式
    • new/delete操作内置类型
    • new和delete操作自定义类型
    • c++推荐是用new和delete
    • operator new与operator delete函数
  • 定位new

1. 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.全局变量,static修饰的全局变量和局部变量都存放在静态区
2.局部变量, 数组存放在栈区
3.const char pChar3= “abcd”; pChar3指向代码段

C语言中动态内存管理

方式:malloc/calloc/realloc/free

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

1.malloc/calloc/realloc的区别是什么?
calloc会初始化。

2. 这里需要free(p2)吗?

C++内存管理方式

C++提出了自己的内存管理方式:通过newdelete操作符进行动态内存管理。

new/delete操作内置类型

void Test()
{
  // 动态申请一个int类型的空间
  int* ptr4 = new int;
  
  // 动态申请一个int类型的空间并初始化为10
  int* ptr5 = new int(10);
  
  // 动态申请10个int类型的空间
  int* ptr6 = new int[3];
  delete ptr4;
  delete ptr5;
  delete[] ptr6;
}

注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用
new[]和delete[].

new和delete操作自定义类型

C++增加了new和delete操作符它最主要的目的是为了处理自定义类型。

class A
{
public:
	A(int a)
		:_a1(a)
	{
		cout << "A(int a)" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _a1;
};
int main()
{
	A* p3 = new A(1);
	delete p3;
	return 0;
}

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

相比于C语言的内存管理,C++还多了初始化

int main()
{
	int* p1 = new int(10); // 申请一个int,初始化10
	int* p2 = new int[10] {1, 2, 3, 4};
`	return 0;
}

c++可以不检查

int main()
{
	int* p1 = new int(10); //失败了抛异常

	int* p2 = (int*)malloc(sizeof(int));//失败了返回0
	if (p2 == nullptr)
	{
		perror("malloc fail");
	}

	return 0;
}

c++推荐是用new和delete

1.new和delete写起来更加简洁
2.new和delete处理自定义类型可以调用构造函数和析构函数

new和delete一定要匹配使用,不然会有各种问题。

operator new与operator delete函数

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

operator new 和operator delete不是运算符重载

operator new 和operator delete本质是对malloc和free的封装,那为什么要这样呢?
这里有一个重要的原因就是,malloc申请内存失败是返回0,而C++希望申请内存失败就抛异常,所以对它进行了封装。

int main()
{
	 //失败了抛异常
	int* p1 = (int*)operator new(sizeof(int*));

	// 失败返回nullptr
	int* p2 = (int*)malloc(sizeof(int*));
	if (p2 == nullptr)
	{
		perror("malloc fail");
	}

调用情况

int main()
{
	// 申请空间 operator new -> 封装malloc
	// 调用构造函数
	A* p5 = new A;
	
	// 先调用析构函数
	// 再operator delete p5指向的空间
	// operator delete -> free
	delete p5;
	
	// 申请空间 operator new[] ->perator new-> 封装malloc
	// 调用10次构造函数
	A* p6 = new A[10];
	
	// 先调用10次析构函数
	// 再operator delete[] p6指向的空间
	delete[] p6;
	return 0;
}

这样写会报错吗?

int* p7 = new int[10];
free(p7);  // 正常释放

不会,这是内置类型。

这样呢?

A* p8 = new A;
free(p8);

free不会调用析构函数,如果有资源需要清理,就会造成内存泄漏。

给大家看一种会出现内存泄漏的情况

int main()
{
	Stack * pst=new Stack;//指针都是内置类型,所以不会调用构造函数
	free(pst);
	return 0;
}

紧接着,我要讲的跟编译器有关,不同的编译器可能会不一样

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

	~A()
	{
		cout << "~A():" << this << endl;
	}
private:
	int _a;
};
int main()
{
	A* p9 = new A[10];
	//free(p9);
	//delete p9;
	delete[] p9;
	return 0;
}

为什么写成free(p9)和delete p9都会报错?
首先我们知道内存泄漏一般是不会报错的,只有比较大的问题才会报错,比如内存错误或者野指针,但是这里为什么会报错呢?
首先A* p9 = new A[10];调用了十次构造函数,所以肯定也要析构十次,那写成delete p9;编译器怎么知道要析构十次呢?
事实上,编译器另外除了开辟A[10]的空间,还往前开了一块大小位为nt的连续的空间,用来存放数据,这个数据告诉编译器要析构多少次。
在这里插入图片描述

写成delete[] p9;表示它会告诉编译器,不是从p9开始析构,而是找到往前再走int大小的地址,开始析构。

报错是因为delete的位置错了,并不是p9那个位置,而不是以为只是析构了一次。

还没有完呢?假设我把析构函数屏蔽掉了还会不会报错。
不会,这是因为自己没有写析构函数,并且编译器会因为没有不需要资源清理而不用生成析构函数。所以自然也不会再往前开辟空间来
存放需要析构的次数,所以delete的位置就是p9;

结论:new/malloc系列 有底层实现机制有关联交叉。不匹配使用
可能有问题,可能没问题,建议大家一定匹配使用

定位new

如果一块已经开好的空间没有初始化,那怎么 初始化呢?
这里就有了定位new这个东西

int main()
{
	A aa;

	A* p1 = (A*)malloc(sizeof(A));
	if (p1 == nullptr)
	{
		perror("malloc fail");
	}

	// 对一块已有的空间初始化 -- 定义new
	new(p1)A(1);
	return 0;
}

析构函数怎么调用?

p1->~A();
free(p1);

直接这样不就可以了

A* p2=new A;

虽然看起来定位new的用处不大,但是定位new有一个特别的应用场景,为了提升性能内存从内存池申请而不是操作系统。
直接new是从操作系统种申请,定位new是从内存池中申请的。

但是内存池也可能伴有一定空间的浪费。

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

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

相关文章

UE4/UE5 材质实现带框环形进度条

UE4/UE5 材质实现带框环形进度条 此处使用版本&#xff1a;UE4.27 原理&#xff1a;大圆减小圆可以得到圆环&#xff0c;大圆环减小圆环&#xff0c;可以得到圆环外围线框 实现效果&#xff1a; 实现&#xff08;为了给大家放进一张面前能看的图&#xff0c;我费劲了心思&…

使用 GPTs 手捏一个代码评分器(两小时速成)

嗨&#xff01;大家好久不见~ ChatGPT 支持 GPTs 也有段时间了&#xff0c;看着应用商店里大神们捏出来的 GPTs , 有些确实很有意思&#xff0c;比如&#xff1a;AI 杠精、模拟面试官、海龟汤… 团子也跃跃欲试&#xff0c;想捏一个 好玩且对大家有用 的 GPTs 出来。 考虑到关注…

如何科学制定营销战略规划?公开课(一)销售罗盘销冠100栏目

上周&#xff0c;销售罗盘&销冠100栏目&#xff0c;重磅推出2场公开课。点击链接查看回放&#xff1a;《如何科学制定营销战略规划&#xff1f;》《如何搭建客户经营体系&#xff1f;》 在第一期公开课《如何科学制定营销战略规划&#xff1f;》中&#xff0c;销售罗盘创始…

Leetcode刷题详解——单词拆分

1. 题目链接&#xff1a;139. 单词拆分 2. 题目描述&#xff1a; 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 **注意&#xff1a;**不要求字典中出现的单词全部都使用&#xff0c;并且字典中的单词可以重复使用。…

TypeScript枚举类型详情、类型断言

一. 概念 TypeScript中的枚举是一种数据类型&#xff0c;它是一组具有预定义名称的有限值的集合。枚举类型可以使代码更加可读、可维护和易于理解。 类似对象&#xff0c;枚举是将一组无序但极度相关数组集合在一起声明存储。 二. 枚举特性 1. 内部进行了双向赋值 enum Numb…

Socket和Http通信原理

Socket是对TCP/IP协议的封装&#xff0c;Socket本身并不是协议&#xff0c;而是一个调用接口&#xff08;API&#xff09;&#xff0c;通过Socket&#xff0c;我们才能使用TCP/IP协议,主要利用三元组【ip地址&#xff0c;协议&#xff0c;端口】。 Http协议即超文本传输协议&a…

VIVADO-FFT IP核学习记录

根据用户手册使用IP核 ① 找到user guide / product guide 并打开 ② 找到Customizing and Generating the Core(不同手册可能题目不一样)&#xff0c;查看IP核的创建过程中各个参数的意义和设置方法。 ③ 找到port description &#xff0c;查看接口注释 根据网络教程使用…

WPS Office JS宏实现批量处理Word中的标题和正文的样式

该篇讲解下word文档中的标题和正文批量修改样式&#xff0c;如下图&#xff1a; 前面一篇已讲解了WPS Office宏编辑器操作方法&#xff0c;这里不细讲了&#xff0c;如有不清楚可以查看该篇&#xff1a;https://blog.csdn.net/jiciqiang/article/details/134653657?spm1001.20…

创建腾讯云存储桶---上传图片--使用cos-sdk完成上传

创建腾讯云存储桶—上传图片 注册腾讯云账号https://cloud.tencent.com/login 登录成功&#xff0c;选择右边的控制台 点击云产品&#xff0c;选择对象存储 创建存储桶 填写名称&#xff0c;选择公有读&#xff0c;私有写一直下一步&#xff0c;到创建 选择安全管理&#…

机器人制作开源方案 | 自主型收集餐盘机器人

作者&#xff1a;蔡佳怡、朱启会、郭晨杰、杨昊天、焦家辉 单位&#xff1a;西安外事学院 指导老师&#xff1a;杜喜昭、张燕 1. 产品说明 1.1 设计目的 对于如学校、工厂这种大型食堂&#xff0c;一般的收餐盘模式为用餐人用餐完毕后&#xff0c;把餐盘拿到最近的收餐盘点&…

5.清除SVN用户账号两种方式

常用的客户端又分为2种&#xff0c;第一种是安装在操作系统中的客户端&#xff0c;另外一种是Eclipse的插件 1.操作系统中的客户端 用的小乌龟&#xff0c;在小乌龟里面先把账户信息删除&#xff1a; 1、随便找一个目录&#xff0c;右键tortoiseSVN-------》setting--------…

【DPDK】Trace Library

概述 跟踪是一种用于了解运行中的软件系统中发生了什么的技术。用于跟踪的软件被称为跟踪器&#xff0c;在概念上类似于磁带记录器。记录时&#xff0c;放置在软件源代码中的特定检测点会生成保存在巨大磁带上的事件&#xff1a;跟踪文件。稍后可以在跟踪查看器中打开跟踪文件…

Windows XP安装SVN软件

SVN全称为SubVersion&#xff0c;是Apache开源软件协议下&#xff0c;一个用于代码分布式管理的工具&#xff0c;其孵化的软件产品是TortoiseSVN&#xff0c;该软件是带图形界面的代码管理工具&#xff0c;类似于Git&#xff0c;多了一个图形界面&#xff0c;方便鼠标操作。  …

【每日OJ —— 145. 二叉树的后序遍历】

每日OJ —— 145. 二叉树的后序遍历 1.题目&#xff1a;145. 二叉树的后序遍历2.解法2.1.算法讲解2.2.代码实现2.3.提交通过展示 1.题目&#xff1a;145. 二叉树的后序遍历 2.解法 2.1.算法讲解 1.首先如果在每次每个节点遍历的时候都去为数组开辟空间&#xff0c;这样的效率太…

MATLAB - 评估拟合优度、评价拟合效果

系列文章目录 文章目录 系列文章目录前言一、如何评估拟合优度二、拟合优度统计2.1 SSE - 误差引起的平方和2.2 R 平方2.3 自由度调整 R 平方2.4 均方根误差 三、MATLAB - 评估曲线拟合度3.1 加载数据并拟合多项式曲线3.2 绘制拟合方程、数据、残差和预测范围图3.3 评估指定点3…

外包干了2个月,技术倒退2年。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;20年通过校招进入深圳某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年国庆&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

c++--面向对象特性

1.面向对象指的是继承&#xff0c;封装&#xff0c;多态。 继承主要关注类的构造&#xff0c;赋值&#xff0c;析构。 以下对多态&#xff0c;封装进行补充说明。 2、多态 2.1.定义 a.赋值 派生类的指针&#xff0c;可以赋值给基类的指针。 派送类的对象&#xff0c;可以赋值给…

某60区块链安全之JOP实战二学习记录

区块链安全 文章目录 区块链安全Jump Oriented Programming实战二实验目的掌握对EVM逆向能力实验环境实验工具实验原理实验内容Jump Oriented Programming实战二 实验步骤Jump Oriented Programming实战二 实验目的 学会使用python3的web3模块 学会分析以太坊智能合约中中Jum…

MySQL_1. mysql数据库介绍

shell脚本差不多快完结了接下来会为大家更新MySQL系列的相关的基础知识笔记&#xff0c;希望对大家有所帮助&#xff0c;好废话不多说&#xff0c;接下来开始正题&#xff01; 1.mysql数据库介绍 mysql 是一款安全、跨平台、高效的&#xff0c;并与 PHP、Java 等主流编程语言…

C#,数值计算——计算实对称矩阵所有特征值与特征向量的三角分解与QL迭代法源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// Computes all eigenvalues and eigenvectors of a real symmetric matrix by /// reduction to tridiagonal form followed by QL iteration. /// </summary> pu…