【C++基础(九)】C++内存管理--new一个对象出来

news2024/11/20 10:38:24

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:C++从入门到精通⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习C++
  🔝🔝


在这里插入图片描述

C++内存管理

  • 1. 前言
  • 2. new
    • 2.1 new的使用方法
    • 2.2 new的特性(对比malloc)
  • 3. delete
    • 3.1 delete的使用方法
    • 3.2 delete的特性(对比free)
  • 4. 全局函数operator new
  • 5. 全局函数operator delete
  • 6. new的实现原理
  • 7. delete的实现原理
  • 8. 总结以及拓展

1. 前言

在C语言中,有四个内存管理函数:
malloc,calloc,realloc和free

但是它们的使用十分的不方便:

int* p=(int*)malloc(sizeof(int)*n);

代码量很大,并且有一个新的问题:

malloc函数不会初始化变量
当变量是自定义类型的时候
C语言的内存管理函数无法
自动调用变量的构造/析构函数!

于是C++祖师爷发话了:
C++要自己搞一个内存管理!

在这里插入图片描述


2. new

2.1 new的使用方法

new的使用方法:

  1. 开辟多个空间
int* p = new int[100];

这段代码可以这样理解:

在这里插入图片描述


  1. 开辟一个空间并初始化
class A
{
public:
 A(int a = 0)
 : _a(a)
 {}
private:
 int _a;
};

A* p = new A(10);

使用小括号()
这段代码初始化了一个对象成10
并且将地址赋值给指针变量p


  1. 开辟多个空间并初始化
A* p = new A[5]{1,2,3};

这段代码可以这样理解:

在这里插入图片描述


2.2 new的特性(对比malloc)

new的特性:

  • 对于内置类型来说,new和malloc
    并没有太大的区别

  • 对于自定义类型来说,new会调用
    自定义类型的构造函数,而malloc不会

  • new可以初始化变量的内容


3. delete

delete对比C语言中的free
是用来使用同台开辟的空间的/1

3.1 delete的使用方法

delete的使用:

  1. 直接使用delete
int* p = new int(10);
//使用指针p
delete p;

当new堆区空间时只开辟了一份空间
释放空间时直接使用delete即可

  1. 使用delete[]
int* p = new int[10]{1,2,3,4};
//使用指针p
delete[] p;

当new使用方括号[]开辟多个空间时
delete也要对应的加上[]来释放空间
否则会出错


3.2 delete的特性(对比free)

delete特性:

  • 对于内置类型,delete和free没有区别

  • 对于自定义类型,delete会调用
    自定义类型的析构函数,而free不会

  • delete面对不同的情况需要加上[ ]
    然而free不用考虑

对于自定义类型来说
有可能类中有指针指向一块堆区
如果不调用析构函数释放这块空间
直接用free释放掉对象的空间
那么这块空间就会内存泄漏!


4. 全局函数operator new

不同于C语言的malloc和free函数
new和delete是两个操作符
那new是怎样开辟空间的呢?

new在底层调用了operator new

注:
operator new是全局函数
不是运算符重载

库中的operator new函数:

void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
void *p;
while ((p = malloc(size)) == 0)
	if (_callnewh(size) == 0)
	{
	    // 如果申请内存失败了,这里会抛出bad_alloc 类型异常
	    static const std::bad_alloc nomem;
	    _RAISE(nomem);
	}
return (p);
}

可以发现,new的底层实际上是
使用了malloc来实现开辟空间

开辟空间成功,会返回指向此空间的指针
开辟空间失败,会抛异常

抛异常不是本节课的重点
它是C++一个全新的知识
在后面的章节会详细介绍
一般情况下,new申请空间都不会失败!


5. 全局函数operator delete

和new对应的delete的底层
也是调用了operator delete来
释放堆区开辟的空间

库中的operator delete函数:

#define free(p) _free_dbg(p, _NORMAL_BLOCK)
void operator delete(void *pUserData)
{
     _CrtMemBlockHeader * pHead;
     RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
     if (pUserData == NULL)
         return;
     _mlock(_HEAP_LOCK);
     __TRY
         pHead = pHdr(pUserData);
         _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
         _free_dbg( pUserData, pHead->nBlockUse );
     __FINALLY
         _munlock(_HEAP_LOCK);
     __END_TRY_FINALLY
     return;
}

看不懂没关系,只需要抓住重点:
delete里面调用了:
_free_dbg(p, _NORMAL_BLOCK)
然而此函数正是free函数定义的宏替换!

说明delete的底层实现实际上
是调用了C语言中的free函数

delete是使用free来释放空间的


6. new的实现原理

对于内置类型来说,new和
malloc的实现是一样的

对于自定义类型来说

  • new的原理步骤
  1. 调用operator new函数申请空间
  2. 在申请的空间上执行构造函数
    完成对象的构造
  • new T[N]的原理步骤
  1. 调用operator new[]函数
    完成N个对象空间的申请
  2. 在申请的空间上执行N次构造函数

7. delete的实现原理

对于内置类型来说,delete
和free的实现是一样的

对于自定义类型来说

  • delete的原理步骤
  1. 在空间上执行析构函数
    完成对象中资源的清理工作
  2. 调用operator delete函数释放对象的空间
  • delete[]的原理步骤
  1. 在释放的对象空间上执行N次析构函数
    完成N个对象中资源的清理
  2. 调用operator delete[]释放空间

8. 总结以及拓展

此章总结完,就可以去new一个对象了
并且C++和C语言中的内存管理区别
是面试中的常考点,和指针与引用的区别
俗称"面试山上的看门二虎"

下面就来总结一下:

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

拓展:内存泄漏

内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费

更多关于内存泄漏的内容:
内存泄漏介绍
内存泄漏原因
内存泄漏检测方法
内存泄漏检测工具

可以参考这两篇文章:

内存泄漏百度百科
内存泄漏分类


🔎 下期预告:C++模板初阶讲解 🔍

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

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

相关文章

RestTemplate发送请求携带文件

在工作上遇到这样一个需求,就是调用我们公司的AI平台,将图片文件发送给他们,他们进行解析然后返回解析结果。 首先用python进行调用一次,发送捕获的接口是这样的: 那么用java代码该如何组装这个请求发送过去呢&#xf…

MIT6.006 课程笔记P1 - 思考如何进行 PeakFinding

文章目录 寻找峰值 peak暴力算法分而治之从1D到2D朴素算法Attemp#2 寻找峰值 peak 给出一个数组 a b c d e f g h i 并给予数字 index 1 2 3 4 5 6 7 8 9 那么如果某个数字是 peak ,那么他将 大于等于左边的数 且 大于等于右边的数 或者 a > b 这里的 a 也是峰值…

Pytest测试框架4

目录: pytest配置文件pytest插件pytest测试用例执行顺序自定义pytest-orderingpytest测试用例并行运行与分布式运行pytest内置插件hook体系pytest插件开发 1.pytest配置文件 pytest.ini 是什么? pytest.ini 是 pytest 的配置文件可以修改 pytest 的…

Sql server还原失败(数据库正在使用,无法获得对数据库的独占访问权)

一.Sql server还原失败(数据库正在使用,无法获得对数据库的独占访问权) 本次测试使用数据库实例SqlServer2008r2版 错误详细: 标题: Microsoft SQL Server Management Studio ------------------------------ 还原数据库“Mvc_HNHZ”时失败。 (Microsoft.SqlServer.…

Java笔记(三十一):MySQL(中)--查询DQL、单表查询、函数、多表查询、查询结果合并

六、查询DQL⭐⭐⭐⭐⭐(SELECT) 0、查询书写顺序&执行顺序 当selcet中有聚合函数时,看起来是 select 先执行,因为后面having可以用到selcet聚合函数后面的别名 但实际上还是select 后执行,如果不是聚合函数或者其…

C#,数值计算——基于模拟退火的极小化问题单纯形(下山)算法的计算方法与C#源程序

1 模拟退火 模拟退火算法其实是一个类似于仿生学的算法,模仿的就是物理退火的过程。 我们炼钢的时候,如果我们急速冷凝,这时候的状态是不稳定的,原子间杂乱无章的排序,能量很高。而如果我们让钢水慢慢冷凝&#xff0c…

PowerDesigner使用实践

PowerDesigner使用实践 一、前言 1.简介 PowerDesigner DataArchitect 是业界领先的数据建模工具。 它提供了一种模型驱动的方法来增强业务和 IT 的能力并使其保持一致。 PowerDesigner 使企业能够更轻松地可视化、分析和操作元数据,以实现有效的企业信息架构。 …

通向架构师的道路之weblogic的集群与配置

一、Weblogic的集群 还记得我们在第五天教程中讲到的关于Tomcat的集群吗? 两个tomcat做node即tomcat1, tomcat2,使用Apache HttpServer做请求派发。 现在看看WebLogic的集群吧,其实也差不多。 区别在于: Tomcat的集群的实现为两个物理上…

Kotin协程的基础

协程是什么? 就是同步方式去编写异步执行的代码。协程是依赖于线程,但是协程挂起的时候不需要阻塞线程。几乎没有任何代价。 协程的创建 一个线程可以创建多个协程。协程的创建是通过CoroutineScope创建,协程的启动方式有三种。 runBlockin…

湘大oj1088 N!:求阶乘 数据太大怎么处理 常规的递归求阶乘

一、链接 N&#xff01; 二、题目 Description 请求N&#xff01;&#xff08;N<10000&#xff09;&#xff0c;输出结果对10007取余 输入 每行一个整数n&#xff0c;遇到-1结束。 输出 每行一个整数&#xff0c;为对应n的运算结果。 Sample Input 1 2 -1 Sample Outp…

【数据结构与算法】左叶子之和

左叶子之和 递归三部曲 确定递归函数的参数和返回值 int sumOfLeftLeaves(TreeNode* root)确定终止条件 遍历遇到空节点 if (root NULL) return 0;单层的递归逻辑 遍历顺序&#xff1a;左右中&#xff08;后序遍历&#xff09; 选择后序遍历的原因&#xff1a;要通过递归函…

【Linux操作系统】深入了解系统编程gdb调试工具

在软件开发过程中&#xff0c;调试是一个非常重要的步骤。无论是在开发新的软件还是维护现有的代码&#xff0c;调试都是解决问题的关键。对于Linux开发者来说&#xff0c;GDB是一个非常有用的调试工具。在本文中&#xff0c;我们将探讨Linux中使用GDB进行调试的方法和技巧。 …

C# OpenCvSharp 读取rtsp流

效果 项目 代码 using OpenCvSharp; using OpenCvSharp.Extensions; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using Syste…

HTTPS安全通信

HTTPS,TLS/SSL Hyper Text Transfer Protocol over Secure Socket Layer,安全的超文本传输协议,网景公式设计了SSL(Secure Sockets Layer)协议用于对Http协议传输的数据进行加密,保证会话过程中的安全性。 使用TCP端口默认为443 TLS:(Transport Layer Security,传输层…

30、Flink SQL之SQL 客户端(通过kafka和filesystem的例子介绍了配置文件使用-表、视图等)

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

【移动机器人运动规划】03 —— 基于运动学、动力学约束的路径规划

文章目录 前言相关代码整理:相关文章&#xff1a; 介绍什么是kinodynamic&#xff1f;为什么需要kinodynamic&#xff1f;模型示例unicycle model&#xff08;独轮车模型&#xff09;differential model&#xff08;两轮差速模型&#xff09;Simplified car model (简化车辆模型…

YOLO相关原理(文件结构、视频检测等)

超参数进化(hyperparameter evolution) 超参数进化是一种使用了genetic algorithm&#xff08;GA&#xff09;遗传算法进行超参数优化的一种方法。 YOLOv5的文件结构 images文件夹内的文件和labels中的文件存在一一对应关系 激活函数&#xff1a;非线性处理单元 activation f…

WWW 23 | Facebook Marketplace的意图理解:用双塔模型处理结构化的产品目录

©PaperWeekly 原创 作者 | 何允中 单位 | Meta 研究方向 | Information Retrieval 摘要 本文介绍了 Facebook Marketplace 团队提出的 HierCat 构架&#xff0c;以解决电商搜索中的意图理解难题。HierCat 利用线上产品交互挖掘弱监督数据&#xff0c;并通过基于 Transfor…

sqlserver 数据库显示 正在还原

问题描述之前不太会搞差异备份的恢复&#xff0c;然后恢复发生了失败之后这个数据库一直处于(正在还原……状态 并且出现数据库无法访问的情况 尝试解决1执行查询Restore Database 数据库名称 with Recovery然后不太能行 2执行查询Restore Database 数据库名称 with NoRecovery…

10个最流行的免费3D模型下载网站

作为一名独立游戏开发者&#xff0c;自己创建图形、配乐、动画和更多东西是相当具有挑战性的。 创建资产所需的成本和时间有时是许多游戏开发商无法承受的。 这就是他们选择在互联网上搜索免费内容的原因。 现在&#xff0c;在浩瀚的内容海洋中获得如此免费的东西有点困难。 本…