当前位置: 首页 > 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…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

FFmpeg avformat_open_input函数分析

函数内部的总体流程如下&#xff1a; avformat_open_input 精简后的代码如下&#xff1a; int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...

Axure 下拉框联动

实现选省、选完省之后选对应省份下的市区...