C++第十一节课 new和delete
一、new和delete操作自定义类型
new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构造函数和析构函数(new会自动调用构造函数;delete会调用析构函数)
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;return 0;
}

通过调试可以发现new可以将值初始化为1;
如果是多个对象:
A* p5 = (A*)malloc(sizeof(A)*10);
A* p6 = new A[10];
free(p5);
delete[] p6;

每个元素都会调用一次构造函数和析构函数!

此时数组会调用默认构造函数将每个元素初始化为0;
如果没有默认构造函数,那么此时需要我们自己向构造函数传递数值;
分析下面的代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class A
{
public:~A(){cout << "~A():" << this << endl;}
private:int _a;
};
int main()
{A* p5 = (A*)malloc(sizeof(A) * 10);A* p6 = new A[10];free(p5);delete[] p6;return 0;
}
上面类中只有系统提供的默认的构造函数,new初始化对象的时候调用系统提供的默认构造函数,但是这个默认构造是跟malloc一样,将数组中的元素初始化为随机值;
如果构造函数不是默认构造函数:
class A
{
public:A(int a): _a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}
private:int _a;
};
int main()
{A* p5 = (A*)malloc(sizeof(A) * 10);A* p6 = new A[4]{1,2,3,4};A* p7 = new A[4]{ A(1),A(2),A(3),A(4) };free(p5);delete[] p6;return 0;
}
这里相当于隐式类型转换:1,2,3,4类型为A,1会调用构造函数(作为参数传递)变为A类型;
等价于下面A* p7!两者是等价的!(A(1),A(2),A(3),A(4)是匿名对象);

- 如果A有默认构造,那么可以采用注释的方式,前三个根据提供的值进行初始化,最后一个根据默认构造进行初始化;
- 如果A没有默认构造,那么必须提供准确的值进行初始化,每个元素都需要提供;
如果new对象再free,malloc再delete出产生什么结果?
对于内置类型,一般不会出现大问题;
但是对于自定义类型:


直接会引发程序崩溃!
原则:一定包匹配使用,否则可能会出现大问题!(结果是不确定的!)

二、operator new与operator delete函数
operator new与operator delete不是一个运算符重载,而是一个全局函数!(库里面的)

free是一个宏函数,底层调用_free_dbg;
malloc如果失败,会返回空,但是面向对象语言处理失败,不喜欢用返回值,更建议用抛异常;

直到返回空然后程序结束;
32位的进程空间总共的寄存器大小为4G(会有4G的虚拟内存 / 堆的总大小不会超过2G);
使用new申请过于大的空间会直接报异常:

可以使用下面的形式捕获异常,catch会捕捉失败的地方(具体语法后面讲):

报异常后会将之前开辟的内存直接释放;

因此,虽然new的功能是:开空间 + 构造函数,开空间部分如果直接调用malloc,那么开辟失败会返回空指针,不会报异常,C++希望的是报异常;
因此引入:operator new,实际上是对malloc的封装,如果失败了会报异常!

因此,实际上new开空间的功能是调用operator new,而operator new实际上是调用malloc!

delete释放空间的功能实际上是调用operator delete函数,而operator delete函数底层是通过封装free函数来实现的!

通过观察可以发现:new实际上就是调用operator new和构造函数!(先开空间再调用构造函数)

同理:delete实际上就是调用operator delete和析构函数(先调用析构函数清理资源,再释放空间;)
三、定位new表达式(placement-new)
分析下面场景:如果我们需要申请一个堆上的栈对象!

调用new的时候,首先,创建的指针变量位于栈区,然后调用operator new在堆上创建对应的成员变量空间!然后会调用构造函数在堆区创建数组空间(堆上的_array指向arr)!

同理:这个过程中,会先调用析构函数清理stack对象指向的资源arr(析构函数释放由于构造函数开辟的资源),operator delete调用free将开辟的成员变量释放!
科普:定位new的用途
如果需要频繁的申请和释放内存(直接在堆上找到合适的空间是一个比较麻烦的事),那么我们可以构造内存池,每次从这个池子中去申请(直接在内存池中申请会比直接在堆上申请快一点);
new是直接在堆上找到合适的内存进行初始化,而我们在内存池中找到的空间没办法进行初始化!
这时候我们可以采用定位new进行初始化!

STL中的链表源码实际上就用到了定位new!

- 这里的construct就是调用定位new;
- destory就是显示调用析构函数;
- 并且代码量少的函数直接设置为内联;
总结:
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
使用格式:
- new (place_address) type或者new (place_address) type(initializer-list)
- place_address必须是一个指针,initializer-list是类型的初始化列表
使用场景:
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。

四、内存泄漏
cout打印int*是按照指针类型进行打印的,但是cout打印char*会将其识别为一个字符串!


对于上面的代码,申请1G的内存,打印的p1会是乱码;
cout将char*识别为一个字符串,打印字符串遇到 \0 才停止,但是上面申请的内存没有进行初始化,因此会一直找 \0 ,且没有初始化的空间为随机值。
因此,我们将其初始化就不会遇到上面的错误!

如果我们想要按照地址打印char*类型怎么办?
方法一:使用printf进行打印(%p);
方法二:使用cout将其转化为(void*)进行打印!

进程结束的时候,操作系统会自动的将进程给回收了;
因此,平时我们运行的时候,就算不手动释放,操作系统会帮我们自动释放;
总结:
- 普通程序,内存泄漏影响不大,进程正常结束会释放资源;
- 长期运行的程序(服务器),内存泄漏危害很大,例如 --- 游戏服务,电商服务......
什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。
五、模板引入
模板分为:函数模板 + 类模板;
引入关键字:template(模板)typename可以缩写为T,其中T被称为模板参数;
函数模板
模板参数定义的是类型;
template<typename T>
void Swap(T& left, T& right)
{T tmp = left;left = right;rifht = tmp;
}int main()
{int a = 0, b = 1;double c = 1.1, d = 2.2;Swap(a, b);Swap(c, d);return 0;
}
问题:对于上面的代码,两次调用的Swap是否是同一个函数?
答案:不是同一个函数!

根据汇编代码可以分析:调用的不是同一个函数,调用根据模板生成的具体的函数(这个过程也叫做模板的实例化);
编译器根据函数模板生成对应具体的函数!
注意点:C++内置自己提供了swap函数,不需要我们自己实现!

底部也是根据模板实现的!
这里的swap可以交换内置类型和自定义类型!
相关文章:
C++第十一节课 new和delete
一、new和delete操作自定义类型 new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间还会调用构造函数和析构函数(new会自动调用构造函数;delete会调用析构函数) class A { public:A(int a 0): _a(a){cout <&l…...
【爱给网-注册安全分析报告-无验证方式导致安全隐患】
前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 1. 暴力破解密码,造成用户信息泄露 2. 短信盗刷的安全问题,影响业务及导致用户投诉 3. 带来经济损失,尤其是后付费客户,风险巨大,造…...
苹果为什么不做折叠屏手机?
苹果为什么不做折叠屏手机?折叠屏手机在最近这些年里边,可以说是市场的一个主要在手机上的增长点。你像华W最近推出这个三折叠手机,引起了整个市场的轰动。 可是,为什么苹果到今天为止不为所动,还在那不停地在现在的这…...
目标检测经典算法的个人理解
one stage 1、RCNN -> Fast-RCNN:RPN部分从用传统的算法 -> 用深度学习网络来实现。 2、Fast-RCNN -> Faster-RCNN:从先选region再求Feature -> 先求Feature再选region。 two stage 1、SSD(2016):VGG做…...
FewShotChatMessagePromptTemplate 和 FewShotPromptTemplate区别
FewShotChatMessagePromptTemplate 和 FewShotPromptTemplate 都是 LangChain 框架中用于少样本学习的提示模板(Prompt Template),但它们在设计和用途上存在一些区别。 FewShotChatMessagePromptTemplate 用途:主要用于聊天场景…...
《程序猿之设计模式实战 · 策略模式》
📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…...
deepinlinux-v23用deepinunioncode初始c例子
deepinlinux-v23用deepinunioncode初始c例子 # deepinunioncode 新建duc工程cmake模版,开局提示 No CMAKE_CXX_COMPILER could be found错误记录 需要duc 左下角磁轮设置 设置cmake和gcc g的文件,如果本机装过了(apt install gc…...
前端框架对比选择:如何在众多技术中找到最适合你的
引言 在现代Web开发中,前端框架的选择对项目的成功与否至关重要。随着技术的不断发展,市面上涌现出多种前端框架,每种框架都有其独特的特点、优缺点以及适用场景。本文将对当前主流的前端框架进行详细对比,帮助开发者在选择时做出…...
数据结构—(java)反射,枚举,lambda表达式
文章目录 反射反射的定义:反射相关的类:反射相关的方法:反射示例:获取Class类对象创建指定类的对象反射私有属性:反射私有方法:反射私有的构造方法 枚举枚举的意义枚举类的实现枚举类的使用:Enu…...
机器学习(西瓜书)第 14 章 概率图模型
14.1 隐马尔可夫模型 机器学习最重要的任务,是根据一些已观察到的证据(例如训练样本)来对感兴趣的未知变量(例如类别标记)进行估计和推测。概率模型(probabilistic model)提供了一种描述框架&a…...
Python异步编程-asyncio详解
目录 asyncio简介示例什么是 asyncio?适用场景API asyncio的使用可等待对象什么是可等待对象?协程对象任务对象Future对象 协程什么是协程?基本使用运行协程 Task什么是 Task?创建 Task取消 TaskTask 异常获取Task 回调 TaskGroup什么是 Tas…...
UniApp如何打包成客户端应用程序
像flutter是支持PC宽屏、桌面平台(Windows/macOS/Linux),我一直在期望UniApp什么时候也支持PC,桌面平台,终于盼到了。 1、支持PC宽屏 从uni-app 2.9起,支持PC宽屏的适配。 uni-app提供的屏幕适配方案&am…...
你应该掌握的12条饭局规矩!
在职场的舞台上,饭局不仅仅是一场简单的聚餐,它是一场精心编排的社交盛宴,是展示个人魅力、构建人脉网络的重要平台。精通饭局的艺术,能让你在职场的交际中更加自如。以下是酱酒亮哥整理的12条饭局指南,希望你在职场的…...
【541. 反转字符串 II 简单】
题目: 给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。 如果剩余字符少于 k 个,则将剩余字符全部反转。如果剩余字符小于 2k 但大于或等于 k 个,…...
基于PHP的丽江旅游管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的丽江旅游管理系统 一 介绍 此丽江旅游系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈:phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销…...
vue3+Element-plus el-input 输入框组件二次封装(支持金额、整数、电话、小数、身份证、小数点位数控制,金额显示中文提示等功能)
一、效果图 二、组件集成了以下功能 1、输入金额--支持千分号显示、可设置decimalLimit来调整小数点位数 2、金额鼠标移入提示中文--标签添加isTip开启中文提示则不允许开启千分号显示showThousands 3、输入手机号--设置inputTypephone 4、输入整数---设置inputTypeinteger 5、…...
jQuery 简介 ③ ready()事件函数、jQuery 二个原则及容错机制
文章目录 jQuery 简介 ③五、ready() 准备就绪时执行代码六、jQuery 核心1、Get and Set in One 原则2、Get first Set all 原则3、容错机制:jQuery 简介 ③ 五、ready() 准备就绪时执行代码 如果我们在中引入jQuery库文件,并编写相应的jQuery代码来操作DOM元素。这很可能导…...
选择Alluxio来解决AI模型训练场景数据访问的五大理由
在AI模型训练尤其是大模型领域,存储系统的性能和稳定性直接决定了模型训练、推理、部署任务的效率和成本。随着全球AI行业的爆发带来的数据规模的快速增长,如何高效管理和利用这些数据成为AI模型训练中的一大挑战。 AI模型训练场景面临的五大难题 1. 数…...
POS共识机制简介
权益证明(Proof of Stake, PoS)共识机制基础 1. 引言 权益证明(Proof of Stake, PoS)是一种用于区块链网络的共识机制,旨在解决工作量证明(Proof of Work, PoW)机制中存在的能源消耗高、中心化…...
Spring为什么要用三级缓存解决循环依赖?
Spring为什么要用三级缓存解决循环依赖? 1. Spring是如何创建一个bean对象2. Spring三级缓存2.1 一级缓存:单例池,经历过完整bean生命,单例Bean对象2.2 二级缓存:提前暴露的Bean2.3 三级缓存:打破循环 3. S…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!
目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...
