当前位置: 首页 > news >正文

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 newoperator 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对于【自定义类型】除了开空间还会调用构造函数和析构函数&#xff08;new会自动调用构造函数&#xff1b;delete会调用析构函数&#xff09; class A { public:A(int a 0): _a(a){cout <&l…...

【爱给网-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…...

苹果为什么不做折叠屏手机?

苹果为什么不做折叠屏手机&#xff1f;折叠屏手机在最近这些年里边&#xff0c;可以说是市场的一个主要在手机上的增长点。你像华W最近推出这个三折叠手机&#xff0c;引起了整个市场的轰动。 可是&#xff0c;为什么苹果到今天为止不为所动&#xff0c;还在那不停地在现在的这…...

目标检测经典算法的个人理解

one stage 1、RCNN -> Fast-RCNN&#xff1a;RPN部分从用传统的算法 -> 用深度学习网络来实现。 2、Fast-RCNN -> Faster-RCNN&#xff1a;从先选region再求Feature -> 先求Feature再选region。 two stage 1、SSD&#xff08;2016&#xff09;&#xff1a;VGG做…...

FewShotChatMessagePromptTemplate 和 FewShotPromptTemplate区别

FewShotChatMessagePromptTemplate 和 FewShotPromptTemplate 都是 LangChain 框架中用于少样本学习的提示模板&#xff08;Prompt Template&#xff09;&#xff0c;但它们在设计和用途上存在一些区别。 FewShotChatMessagePromptTemplate 用途&#xff1a;主要用于聊天场景…...

《程序猿之设计模式实战 · 策略模式》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…...

deepinlinux-v23用deepinunioncode初始c例子

deepinlinux-v23用deepinunioncode初始c例子 # deepinunioncode 新建duc工程cmake模版&#xff0c;开局提示 No CMAKE_CXX_COMPILER could be found错误记录 需要duc 左下角磁轮设置 设置cmake和gcc g的文件&#xff0c;如果本机装过了&#xff08;apt install gc…...

前端框架对比选择:如何在众多技术中找到最适合你的

引言 在现代Web开发中&#xff0c;前端框架的选择对项目的成功与否至关重要。随着技术的不断发展&#xff0c;市面上涌现出多种前端框架&#xff0c;每种框架都有其独特的特点、优缺点以及适用场景。本文将对当前主流的前端框架进行详细对比&#xff0c;帮助开发者在选择时做出…...

数据结构—(java)反射,枚举,lambda表达式

文章目录 反射反射的定义&#xff1a;反射相关的类&#xff1a;反射相关的方法&#xff1a;反射示例&#xff1a;获取Class类对象创建指定类的对象反射私有属性&#xff1a;反射私有方法&#xff1a;反射私有的构造方法 枚举枚举的意义枚举类的实现枚举类的使用&#xff1a;Enu…...

机器学习(西瓜书)第 14 章 概率图模型

14.1 隐马尔可夫模型 机器学习最重要的任务&#xff0c;是根据一些已观察到的证据&#xff08;例如训练样本&#xff09;来对感兴趣的未知变量&#xff08;例如类别标记&#xff09;进行估计和推测。概率模型&#xff08;probabilistic model&#xff09;提供了一种描述框架&a…...

Python异步编程-asyncio详解

目录 asyncio简介示例什么是 asyncio?适用场景API asyncio的使用可等待对象什么是可等待对象&#xff1f;协程对象任务对象Future对象 协程什么是协程&#xff1f;基本使用运行协程 Task什么是 Task&#xff1f;创建 Task取消 TaskTask 异常获取Task 回调 TaskGroup什么是 Tas…...

UniApp如何打包成客户端应用程序

像flutter是支持PC宽屏、桌面平台&#xff08;Windows/macOS/Linux&#xff09;&#xff0c;我一直在期望UniApp什么时候也支持PC&#xff0c;桌面平台&#xff0c;终于盼到了。 1、支持PC宽屏 从uni-app 2.9起&#xff0c;支持PC宽屏的适配。 uni-app提供的屏幕适配方案&am…...

你应该掌握的12条饭局规矩!

在职场的舞台上&#xff0c;饭局不仅仅是一场简单的聚餐&#xff0c;它是一场精心编排的社交盛宴&#xff0c;是展示个人魅力、构建人脉网络的重要平台。精通饭局的艺术&#xff0c;能让你在职场的交际中更加自如。以下是酱酒亮哥整理的12条饭局指南&#xff0c;希望你在职场的…...

【541. 反转字符串 II 简单】

题目&#xff1a; 给定一个字符串 s 和一个整数 k&#xff0c;从字符串开头算起&#xff0c;每计数至 2k 个字符&#xff0c;就反转这 2k 字符中的前 k 个字符。 如果剩余字符少于 k 个&#xff0c;则将剩余字符全部反转。如果剩余字符小于 2k 但大于或等于 k 个&#xff0c;…...

基于PHP的丽江旅游管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的丽江旅游管理系统 一 介绍 此丽江旅游系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈&#xff1a;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模型训练尤其是大模型领域&#xff0c;存储系统的性能和稳定性直接决定了模型训练、推理、部署任务的效率和成本。随着全球AI行业的爆发带来的数据规模的快速增长&#xff0c;如何高效管理和利用这些数据成为AI模型训练中的一大挑战。 AI模型训练场景面临的五大难题 1. 数…...

POS共识机制简介

权益证明&#xff08;Proof of Stake, PoS&#xff09;共识机制基础 1. 引言 权益证明&#xff08;Proof of Stake, PoS&#xff09;是一种用于区块链网络的共识机制&#xff0c;旨在解决工作量证明&#xff08;Proof of Work, PoW&#xff09;机制中存在的能源消耗高、中心化…...

Spring为什么要用三级缓存解决循环依赖?

Spring为什么要用三级缓存解决循环依赖&#xff1f; 1. Spring是如何创建一个bean对象2. Spring三级缓存2.1 一级缓存&#xff1a;单例池&#xff0c;经历过完整bean生命&#xff0c;单例Bean对象2.2 二级缓存&#xff1a;提前暴露的Bean2.3 三级缓存&#xff1a;打破循环 3. S…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...