【深入理解C++】new/delete和new[]/delete[]探秘

news2024/12/25 9:13:28

文章目录

  • 1.operator new()和operator delete()
  • 2.new记录分配的内存大小供delete使用
  • 3.new[]/delete[]申请和释放一个数组
    • 3.1 基本数据类型(内置类型)
    • 3.2 自定义类型(类类型)
  • 4.new/delete和new[]/delete[]要配对使用

1.operator new()和operator delete()

在这里插入图片描述

operator new() 和 operator delete() 是函数。

new 干了两个事情:

  1. 在堆中分配内存:通过 operator new() 来分配内存
  2. 调用构造函数来初始化内存

delete 也干了两个事:

  1. 调用析构函数
  2. 释放内存:调用 operator delete() 来释放内存

2.new记录分配的内存大小供delete使用

int *p = new int; // 4字节
delete p;

删除的时候,编译器怎么知道要回收的是 4 字节?

答:new 内部有记录机制,记录了分配出去多少内存。

new 如何记录分配的内存大小供 delete 使用?

答:不同的编译器,new 内部有不同的实现方式。

3.new[]/delete[]申请和释放一个数组

3.1 基本数据类型(内置类型)

举例1:

#include <iostream>
using namespace std;

int main()
{
	int* p = new int(100); // 如果不释放,会泄漏4字节
	delete p;

	return 0;
}

举例2:

#include <iostream>
using namespace std;

int main()
{
	int* p = new int[2]; // 如果不释放,会泄漏8字节
	delete[] p;

	return 0;
}

3.2 自定义类型(类类型)

举例1:

#include <iostream>
using namespace std;

class A
{
public:
	A()
	{
		cout << "A::A()" << endl;
	}
	~A()
	{
		cout << "A::~A()" << endl;
	}
};

int main()
{
	A* p = new A(); // 如果不释放,会泄漏1字节
	delete p;

	return 0;
}

在这里插入图片描述

举例2:

#include <iostream>
using namespace std;

class A
{
public:
	A()
	{
		cout << "A::A()" << endl;
	}
	~A()
	{
		cout << "A::~A()" << endl;
	}
};

int main()
{
	A* p = new A[2](); // 如果不释放,会泄漏6字节
	delete[] p;

	return 0;
}

在这里插入图片描述

疑问:为什么给类型 A 对象数组动态分配内存时多出来 4 个字节,而给内置类型 int 数组动态分配内存时并没有多出来 4 字节?

在上面的程序中,对于类类型 A,调用了两次构造函数、两次析构函数,也就是说,delete一个数组时,要为每一个数组元素调用析构函数。

但是,对于 delete 表达式,它并不知道数组的元素个数,只有 operator new() 函数和 operator delete() 函数知道。因此,必须有一种手段来告诉 delete 表达式的数组大小是多少。

那么,一种可行的方式就是,多分配一个大小为 4 字节的空间来记录数组大小,同时可以约定前 4 字节来记录大小。那么,由 operator new() 函数分配的地址与 new 表达式返回的地址应该相差 4 个字节。

当然,对于非类类型数组和不需要调用析构函数的类类型数组,这多余的 4 字节就不需要了。

4.new/delete和new[]/delete[]要配对使用

举例1:

#include <iostream>
using namespace std;

int main()
{
	int* pi = new int[3]; // 如果不释放,会泄漏12字节
	//delete pi; // 这里即使用delete释放,也不会发生内存泄漏	
	delete[] pi; // 这种释放方法才是最规范的

	return 0;
}

举例2:

#include<iostream>
using namespace std;

class A
{
public:
	A()
	{
		cout << "A::A()" << endl;
	}

	// 没有自定义的析构函数
};

int main()
{
	A* pa = new A[2](); // 如果不释放,会泄漏2字节
	//delete pa; // 这里即使用delete释放,也不会发生内存泄漏
	delete[] pa; // 这种释放方法才是最规范的

	return 0;
}

举例3:

#include <iostream>
using namespace std;

class A
{
public:
	A()
	{
		cout << "A::A()" << endl;
	}
	~A()
	{
		cout << "A::~A()" << endl;
	}
};

int main()
{
	A* pa = new A[2](); // 如果不释放,会泄漏6字节
	//delete pa; // 这里如果用delete释放,系统就会报告异常
	delete[] pa; // 这种释放方法才是最规范的

	return 0;
}

在这里插入图片描述

为什么自己一提供析构函数,不用 delete[] 来释放 new[] 出来的内存就报异常呢?

从上图中可以看出,只调用了 1 次 A 的析构函数而不是 2 次,表示肯定有内存泄漏。真正释放内存的是 operator delete() 函数,而多出来的 4 个字节导致释放内存空间错乱。

结论:如果一个对象(内置对象、类对象),使用 new[] 来分配内存,却用单独的 delete(而不是 delete[])来释放内存,那么这个对象需要满足的条件是:对象的类型要么是内置类型或者无自定义的析构函数的类类型。

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

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

相关文章

开发 Chrome 扩展 之 Hello World 心血来潮

开发 Chrome 扩展 Hello, World 项目加载未打包的扩展icon刷新引入 JS 与错误处理 开发 Chrome 扩展 开发 Chrome 扩展除了需要基本的 HTML, CSS, JS 之外, 还可以使用 Chrome 额外提供的 API. 除了需要的 .html, .css 和 .js 文件之外呢, 扩展还包括不同类型的文件, 具体可…

杨辉三角形(Java版)

不为失败找理由&#xff0c;只为成功找方法。所有的不甘&#xff0c;因为还心存梦想&#xff0c;所以在你放弃之前&#xff0c;好好拼一把&#xff0c;只怕心老&#xff0c;不怕路长。 文章目录1. 什么是杨辉三角形2. 实现思路&#xff08;方式&#xff09;2.1 递归方式2.2 递归…

Nginx简单使用

安装龙蜥操作系统 镜像文件在这里下载就行 下载之后新建虚拟机 ISO选择刚才下载文件即可 具体配置可以照我来 也可自定义 基本工具安装 安装一下最基本的网络工具 yum install net-tools openssh-server wget tar make vim -y测试一下ssh连接 方便后期操作 修改主机名 …

Jedis 使用教程总结

一、Redis 常用命令 1 连接操作命令 quit&#xff1a;关闭连接&#xff08;connection&#xff09;auth&#xff1a;简单密码认证help cmd&#xff1a; 查看 cmd 帮助&#xff0c;例如&#xff1a;help quit 2 持久化 save&#xff1a;将数据同步保存到磁盘bgsave&#xff…

设计模式之原型模式

文章目录1.前言概念使用场景2.原型模式核心组成UML图3.浅拷贝与深拷贝基本类型与引用类型浅拷贝代码演示深拷贝代码演示4.原型模式的优点与缺点1.前言 概念 原型模式&#xff08;Prototype Pattern&#xff09;是用于创建重复的对象&#xff0c;同时又能保证性能。这种类型的…

Cpp知识点系列-类型转换

前言 在做题的时候发现了需要用到类型转换&#xff0c;于是在这里进行了简单的记录。 历史原因&#xff0c;慢慢整理着发现类型转换也能写老大一篇文章了。又花了时间来梳理一下就成了本文了。 cpp 之前使用的环境是DEV-C 5.4&#xff0c;而对应的GCC版本太低了。支持c11需要…

【CSS】重点知识梳理,这样上手无压力

推荐前端学习路线如下&#xff1a; HTML、CSS、JavaScript、noodJS、组件库、JQuery、前端框架&#xff08;Vue、React&#xff09;、微信小程序和uniapp、TypeScript、webpack 和 vite、Vue 和 React 码源、NextJS、React Native、后端内容。。。。。。 CSS定义&#xff1a; …

docker入门到精通一文搞定

文章目录前言一、Docker概述1.Docker为什么会出现&#xff1f;2.Docker相比VM技术3.Docker 能做什么&#xff1f;3.1 比较Docker和虚拟机技术的不同&#xff1a;3.2 DevOps (开发、运维)&#xff1a;4个特点二、Docker安装1.dokcer架构图&#xff1a;2.Docker基本组成&#xff…

python+django体质测试数据分析及可视化设计

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 B/S架构 4 本选题则旨在通过标签分类管理等方式&#xff0c;实现管理员&#xff1a;管理员&#xff1a;首页、个…

11.前端笔记-CSS盒子模型-外边距margin

1、margin 1.1 margin的语法 盒子与盒子之间的距离 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewpor…

linux 系统的磁盘 mbr 转gpt方法

linux磁盘用fdisk格式化挂盘的格式都为mbr, 不支持大于2T的磁盘扩容&#xff0c;需要用parted转化。 查询磁盘格式 输入&#xff1a; fdisk -l 看Disk label type 的值&#xff0c;是dos 的为mbr 是gpt的为gpt 当前&#xff0c;因挂盘时&#xff0c;用的fdisk方式选gpt,挂…

基于STM32的u8g2移植以及学习

实验硬件&#xff1a;STM32F103C8T6&#xff1b;0.96寸OLED&#xff08;12864&#xff09; U8g2库开源网址&#xff1a;https://github.com/olikraus/u8g2 一、u8g2库知识 1.1 什么是u8g2&#xff1f; U8g2是嵌入式设备的单色图形库。主要应用于嵌入式设备&#xff0c;包括我…

正大国际期货:投资外盘期货如何运用K线图中十字星形态?

很多人都明白&#xff0c;做外盘期货需要学会看线图。那么K线图上面的一根两根的柱子代表的什么意思呢&#xff1f;其中星星点点的十字星又是什么意思&#xff1f;下面正大IxxxuanI详细给大家讲解一下&#xff01; 1、什么是多头十字星形态&#xff1f; 多头十字星是一种经典…

KEITHLEY 吉时利2601B源表产品技术参数

KEITHLEY 2601B 吉时利 2601B 源表让您可以比以前更快、更轻松、更经济地进行精密直流、脉冲和低频交流源测量测试。Keithley 2601B 通过结合以下特性&#xff0c;为 IV 功能测试提供竞争产品 2 到 4 倍的测试速度&#xff1a; 吉时利的高速第三代源测量单元 (SMU) 设计 嵌…

【Python】八、函数的使用

文章目录实验目的一、定义函数二、调用函数三、参数的传递和函数的返回值四、编写函数&#xff0c;输入不同的参数&#xff0c;绘制不同的科赫曲线参考代码实验截图实验目的 掌握函数的定义和调用&#xff1b;掌握函数的用法&#xff1b;理解递归&#xff1b;培养学生动手查阅资…

开源:分享4个非常经典的CMS开源项目

❤️作者主页&#xff1a;IT技术分享社区 ❤️作者简介&#xff1a;大家好,我是IT技术分享社区的博主&#xff0c;从事C#、Java开发九年&#xff0c;对数据库、C#、Java、前端、运维、电脑技巧等经验丰富。 ❤️个人荣誉&#xff1a; 数据库领域优质创作者&#x1f3c6;&#x…

Spark系列之Spark安装部署

title: Spark系列 第二章 Spark安装部署 2.1 版本选择 下载地址&#xff1a; https://archive.apache.org/dist/spark 四大主要版本 Spark-0.X Spark-1.X&#xff08;主要Spark-1.3和Spark-1.6&#xff09; Spark-2.X&#xff08;最新Spark-2.4.8&#xff09; Spark-3.x&a…

降级、熔断和限流———一看就会

设定&#xff1a;A上游系统、B本系统、C下游系统 服务降级 服务降级是从整个系统B的负荷情况出发和考虑的&#xff0c;对某些负荷会比较高的情况&#xff0c;为了预防某些功能&#xff08;业务场景&#xff09;出现负荷过载或者响应慢的情况&#xff0c;在B其内部暂时舍弃对一…

【Mybatis编程:统计相册表中的数据的数量】

目录 1. 书写SQL语句 2.在AlbumMapper.java接口中添加抽象方法 3. 在AlbumMapper.xml中配置SQL语句 4. 在AlbumMapperTests.java中编写并执行测试 1. 书写SQL语句 需要执行的SQL语句大致是&#xff1a; select count(*) from pms_album 在设计抽象方法时&#xff0c;如果要…

【三维重建补充知识-0】视差、深度概念及其转换

一、基本概念 把手指放在眼前&#xff0c;分别闭上左、右眼&#xff0c;我们会发现手指与后边物体的相对位置是不同的&#xff0c;也即两眼所识别的两幅图像之间存在视觉差异&#xff0c;我们通过“视差”这一概念来表示这种差别。 该过程也可以通过两个处于同一平面的相机来模…