delete释放new[] 以及 delete[]释放new 的问题

2023-05-16

同花顺的笔试过程中遇到这么一个类似问题:

A* ptr = new A[10];
for(int i = 0;i < n;i++){
    delete &ptr[i];
}

由此衍生出两个问题:

  1. new[] 申请的空间用delete释放会发生什么
  2. new 申请的空间用delete[] 释放会发生什么

下面就让我们来探索一下其中的奥秘

一.new[]申请的空间用delete释放

1.内置类型

如int,char,float,double等内置类型这样操作是没有什么问题的.

int main() {
    //以内置类型int为例:
	int* ptr = new int[10];
	delete ptr;
	return 0;
}

如上代码,在执行delete ptr之后,可以看到这一片连续的空间被释放.

2.自定义类型

如c语言中的结构体,枚举,联合体,C++中的类.自定义类型这样操作是有问题的.

class A {
public:
	int _sum;
	~A() {
		cout << "调用析构" << endl;
	}
};
int main() {
	A* ptr = new A[10];
	delete ptr;
	return 0;
}

 执行delete ptr时程序,只输出了一句"调用析构",便异常终止了.

原理:

new/new[] 和 delete/delete[]的原理: new和delete在底层实际是分别封装了operator new 和 operator delete两个全局函数,而operator new 和 operatordelete 在底层又分别封装了malloc() 和 free().

内置类型为何不会出错:

以上面代码中的内置类型int为例,new int[10]时底层实际是malloc申请了10个int类型数据的空间(也就是40字节).当delete时,最底层用free直接释放,显然是没有问题的.

自定义类型为何会出错:

以上面代码中的类A为例,new A[10]时,与int的处理方式不同.

对于自定义类型,new在最底层用malloc申请空间后,会调用类A的构造函数,对每个元素进行初始化等操作.

这里需要注意的是 当new[] 分配的类型时自定义类型时,new[]会让malloc在分配空间时多申请4字节,new[]返回的是底层malloc返回地址向后偏移4字节的地址.如下图所示:

具体到new int[10]时,malloc本应该申请10个A类型大小的空间,也就是40个字节,但是此时malloc实际上申请了44个字节,new返回的指针是malloc返回的指针向后偏移4个字节的地址.

这4个字节存放着所申请自定义元素的个数.

那么前面说free自己可以通过传入一个指针就知道释放多大的空间,那么增加这4个字节来存放元素个数岂不是多次一举?

很有必要讲一下delete[]的原理: delete[]会把new[]所返回的指针向前偏移4个字节的地址返回给free,因此free就能正确的释放掉整片空间.

A* ptr = new A[10]的正确搭配是delete[] ptr,那么delete[]此时获取到的指针是new[]的返回值(并不是malloc所申请空间的首地址),这样的话底层的free并不能通过这个指针释放掉这片空间,但是delete[]hi把new所返回的指针向前偏移4个字节位置的地址给free.

多出来4个字节保存着自定义元素的个数的作用:

一个对象在释放空间前需要调用析构函数来完成一些资源的清理工作.那么问题来了,delete[] 没有像new A[10]传参进去,delete[]怎么知道调用多少次析构.

其实多出来的4个字节存的元素个数,就是用来让delete[]知道调用多少次析构函数的.

了解完delete[]的原理,再回到上面代码具体出错的原因.

new出来的10个对象,执行delete ptr时,先调用一次析构函数完成对第一个对象的析构,后面9个都不会析构,因为delete对应的new都是单个元素的操作(new返回的是malloc返回的指针,delete也只调用一次析构),而此时的ptr并不是malloc返回的首地址,所有delete在底层调用free时,给free传入了一个free无法识别的指针,程序就会崩溃.(因此上面的程序运行后只打印了一次调用析构就崩溃了)

小结:

  1. new[]在给自定义类型空间时,会多分配4个字节用来存储元素个数.通过*(int*)(ptr-1)就能看到或者直接查看内存也可以看到.所以delete用此时new[]返回的指针来调用自己底层的free时,free就出错了,程序就会崩溃.
  2. new[]在给内置类型申请空间时,不会存储元素个数,因为自定义类型delete[]时没有析构函数可调用(所以没必要存储),free不会出错

二.new申请的空间用delete[]释放

1.内置类型

当类型是内置类型时,delete[]和delete一样,所以不会出现问题.

int main() {
	int* ptr = new int();
	delete[] ptr;
 	return 0;
}

2.自定义类型

会出现错误, 原因是也是前面讲过了, 当类型是自定义类型时 delete[ ] p 会先根据p前面4字节中的元素个数来确定调用析构函数的次数,

先到用析构函数, 前四个字节的内存是非法内存, 其中的值是随机的, 所以说调用析构次数也是随机的, 通常这个数很大, 所以会调用很多次析构, 再把接收的指针p往前4字节的地址给底层的free(注意, 往前4字节, 这四字节是没有被申请的空间).

由于free不能释放没有被申请的空间, 所以free出错, 而且free也不能通过这个p往前4字节的地址知晓到底释放多大的空间, 也会出错 (free只能通过malloc返回的地址知道要释放多大空间).

class A {
public:
	int _sum;
	~A() {
		cout << "调用析构" << endl;
	}
};
int main() {
	A* ptr = new A();
	delete[] ptr;
 	return 0;
}

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

delete释放new[] 以及 delete[]释放new 的问题 的相关文章

  • c++new操作符笔记

    c 43 43 new语句 功能 xff1a 堆区开辟一组数据 语法 xff1a new 数据类型 注意点 xff1a new创建的数据会返回该数据对应的类型指针 xff0c 另外堆区开辟的数据由程序员手动释放
  • 攻防世界 web 不能按的按钮 disabled_button

    f12打开开发者工具 点击查看器这一栏 定位到它的图标处 双击进入 里面有代码如下 一般有两种方法 方法一 删除代码 disabled 然后点击网页上的flag图标就可以得到flag了 方法二 将disabled 改为disabled fa
  • 剖析C++标准库智能指针(std::auto_ptr)

    1 Do you Smart Pointer Smart Pointer 中文名 智能指针 舶来品 不可否认 资源泄露 resource leak 曾经是C 程序的一大噩梦 垃圾回收 机制 Garbage Collection 一时颇受注目
  • Java实现判断是否为最新版本方法

    判断是否为最新版本方法 将版本号根据 切分为int数组 比较 param localVersion 本地版本号 param onlineVersion 线上版本号 return 是否为新版本 throws IllegalArgumentEx
  • 私有构造函数

    通常我们都将构造函数的声明置于public区段 假如我们将其放入private区段中会发生什么样的后果 没错 我也知道这将会使构造函数成为私有的 这意味着什么 我们知道 当我们在程序中声明一个对象时 编译器为调用构造函数 如果有的话 而这个
  • c++函数返回引用

    转自 http www cnblogs com floatedclouds archive 2011 10 13 2209917 html 1 什么是引用 引用就是变量的别名 操作一个变量的引用也就相当于操作变量本身 这一点跟指针很类似 但
  • 复制文件夹所有内容 和 删除整个文件夹的2个函数

    选择自 hycapril 的 Blog 实现一个静态方法将指定文件夹下面的所有内容copy到目标文件夹下面 如果目标文件夹为只读属性就会报错 April 18April2005 In STU public static void CopyD
  • C++选择题

    选择题 1 说明函数int method a floct 是友元函数应为 A A friend int method a a floctz B friend int method a floctz C int friend a floctz
  • OpenBSD cvsup更新

    安装了 OpenBSD 后你会发现它很小个 只有500多M 当然里面只有ssh sendmail功能 dev wd0a 130M 38 8M 84 7M 31 dev wd0h 95 5G 16 0K 90 8G 0 home dev wd
  • c++ 内存管理一:初识内存分配工具

    文章目录 前言 1 new 和 delete 2 new 和delete 3 operator new 4 placement new 5 malloc和free 6 allocator 前言 侯捷 c 内存管理学习总结笔记 在C 中 有几
  • 查询及删除重复记录

    查询及删除重复记录的方法大全 1 查找表中多余的重复记录 重复记录是根据单个字段 peopleId 来判断select from peoplewhere peopleId in select peopleId from people gro
  • VC 根据域名获取IP

    include Winsock2 h pragma comment lib Ws2 32 lib 注意字符串需以 0结尾 例如 lpzSeverName www baidu com 0 bool WINAPI Domain2IP char
  • C++模板特例化

    模板是用来写一些独立化特定类型的代码 但是对于有些类型 在处理时 细节上却有所差别 常见的如char 如 现在你打算写一个栈 可以用于任何数据类型 那你肯定首先想到的就是模板啦 template
  • 类的构造函数和析构函数

    1 把对象的初始化工作放在构造函数中 把清除工作放在析构函数中 当对象被创建时 构造函数被自动执行 当对象消亡时 析构函数被自动执行 这下就不用担心忘了对象的初始化和清除工作 2 构造函数 析构函数与类同名 由于析构函数的目的与构造函数的相
  • 非printf形式打印各种数据类型的十六进制和二进制

    转载请标明是引用于 http blog csdn net chenyujing1234 欢迎大家提出意见 一起讨论 一 源码实现 为了适配各种数据类型 且可以通过sizeof得到此类型的大小 所以这里采用模板形式开发 以下是实现此功能的源码
  • PL/SQL程序设计_基本语法

    DECLARE V DATE DATE SYSDATE v var VARCHAR2 20 V VALID BOOLEAN BEGIN IF V VAR IS NULL THEN DBMS OUTPUT PUT LINE V VAR IS
  • SQL删除重复数据只保留一条

    用SQL语句 删除掉重复项只保留一条 在几千条记录里 存在着些相同的记录 如何能用SQL语句 删除掉重复的呢1 查找表中多余的重复记录 重复记录是根据单个字段 peopleId 来判断 select from people where pe
  • memset in C++ and C

    definition memset是计算机中C C 语言函数 将s所指向的某一块内存中的前n个 字节的内容全部设置为ch指定的ASCII值 第一个值为指定的内存地址 块的大小由第三个参数指定 这个函数通常为新申请的内存做初始化工作 其返回值
  • delete LEFT JOIN 的一个问题解决办法

    LEFT JOIN 的一个问题解决办法 今天在一个程序后台删除一个东西的时候 却出现了这个问题 Java代码 System Message MySQL Query Error User admin Time 2007 10 20 21 08
  • 如何正确的关闭 MFC 线程

    前言 近日在网上看到很多人问及如何关闭一下线程 但是我看网上给出的并不详细 而且有些方法还是错误的 小弟在此拙作一篇 不谈别的 只谈及如何正确的关闭MFC的线程 至于Win32和C RunTime的线程暂不涉及 一 关于MFC的线程 MFC

随机推荐

  • unity 3D:自动寻路

    首先 xff0c 搭建一下场景 xff0c 场景要求 xff1a 有遮挡 xff0c 设置好不可走区域为navigation static 以及 not walkable 在人身上添加Nav Mesh Agent 设置好后勾选显示导航网格
  • Java高级特性反射与动态代理模式

    文章目录 前言一 了解反射二 继续了解反射 xff08 哈哈哈 xff09 1 每一个类对应的class放在哪里 xff1f 2 这个class里面都保存了什么3 如何使用 xff1f 3 1 获取类加载器3 2 获取构造器对象3 3 获取
  • Unity3D 使用SceneManager跳转/加载场景

    很久没有更新博客了 xff0c 最近也是还在学习U3D 下面写一下使用SceneManager跳转 加载场景 我们假设要点击一个按钮跳转 xff0c 那么我们只要把跳转的代码写进按钮点击事件里就好了 其实加载场景很简单 xff0c 只需要写
  • Hisat2 Bowtie2比对结果解读

    Bowtie的中文意思是 xff1a 领结 xff0c 蝴蝶结 Bowtie2用户手册 xff1a http bowtie bio sourceforge net bowtie2 manual shtml 在看比对结果前需要了解三个概念 x
  • React 项目启动报错:The “path” argument must be of type string

    今天下载一个旧的React项目 xff0c yarn start 运行 xff0c 报错 xff1a TypeError ERR INVALID ARG TYPE The path argument must be of type stri
  • Android 身份认证基本概念

    身份验证 Android 采用通过用户身份验证把关的加密密钥机制 xff0c 该机制需要以下组件 xff1a 加密密钥存储和服务提供程序 存储加密密钥并基于这些密钥提供标准加密例程 Android 支持由硬件支持的密钥库和 Keymaste
  • Gnome增加消息提醒extension 适用于聊天工具如xchat "message notifier" "notifications alert" "permanent notification&quo

    使用如xchat这样的聊天工具 xff0c 有人跟你说话时 xff0c 在KDE桌面中 xff0c 默认系统托盘中的xchat托盘会闪烁 xff0c 直到你点击将xchat切换到前台 xff0c 这是xchat在preference可以设置
  • 读取文件报错:FileNotFoundError: [Errno 2] No such file or directory

    文章目录 问题描述问题分析解决办法 问题描述 使用 img 61 Image open 39 data DSC 8923 jpg 39 读取一张图片时 xff0c 报 FileNotFoundError Errno 2 No such fi
  • CentOS7离线安装图像化界面踩坑及脱坑历程

    CentOS7离线安装图像化界面 背景安装问题尝试一 xff1a 尝试二 xff1a 其他问题总结 背景 很久之前实验室的一台服务器安装了CentOS 7 6 1810版本的linux系统 xff0c 然而当时安装系统的同学不知出于什么目的
  • Eslint 配置及规则说明

    中文官方网站 基本使用教程 安装 可以全局安装 xff0c 也可以在项目下面安装 如下是在项目中安装示例 xff0c 只需要在 package json 中添加如下配置 xff0c 并进行安装 xff1a gt 34 eslint 34 3
  • Ubuntu自动登录图形系统界面(免密码、开机自启动)

    Ubuntu自动登录图形系统界面 xff08 免密码 开机自启动 xff09 操作系统版本 xff1a 18 04 修改50 unity greeter conf xff0c 使其允许root登录 span class token func
  • 学C++有多难,你知道吗?

    都2020年了 xff0c 还要学C 43 43 吗 xff1f C 43 43 好多理工科大学里面都有 xff0c 它的学习难度比其他编程语言比如Python Javascript 和Java等等难 那为什么呢 xff1f C 43 43
  • 搞懂Java高级特性--注解

    1 注解是什么 xff1f Java注解 xff08 Annotation xff09 又称Java标注 xff0c 是JDK5 0引入的一种注释机制 xff0c 注解是元数据的一种形式 xff0c 提供有关于程序但不属于程序本身的数据 x
  • 为什么都说代码改变世界?是因为这五位程序员创造了未来!

    致敬那些为软件开发奠定坚实基础的计算机科学先驱 从 1 和 0 开始 xff0c 编程经历了很长一段路 xff0c 才达到了现在的抽象状态 过去的程序员用伟大的发明 xff0c 为现代程序员轻松地完成工作奠定了坚实的基础 如果我们研究某个软
  • 编译提示缺少libjli.so,jar command not found,javadoc错误等

    这周一周忙于Ubuntu server环境下的Android编译环境的搭建 xff0c 由于刚开始真正使用Linux xff0c xff08 以前虽然用过Ubuntu xff0c 但是就当win用了 就这样还没坚持下来 xff0c 现在工作
  • 银河麒麟系统4.0.2离线安装MySQL教程

    银河麒麟系统4 0 2离线安装MySQL教程 xff08 Ubuntu离线安装MySQL教程 xff09 https www jianshu com p 478dc7c9b9e0 这个教程很详细 xff0c 我不再多说 xff0c 而且亲测
  • 实现线程同步的几种方式

    在多线程中线程的执行顺序是依靠哪个线程先获得到CUP的执行权谁就先执行 xff0c 虽然说可以通过线程的优先权进行设置 xff0c 但是他只是获取CUP执行权的概率高点 xff0c 但是也不一定必须先执行 在这种情况下如何保证线程按照一定的
  • STC开天斧虚拟示波器使用

    开天斧外观图 xff0c 颜值非常可以 1 在keil中添加STC8H8K64U的型号和头文件 xff0c 添加功能在STC IPS软件里 首先点击Keil仿真设置 xff0c 然后选择单片机型号STC8H8K64U xff0c 然后点击添
  • android AlertDialog 弹窗自定义布局 点击外部不关闭弹窗

    AlertDialog span class token punctuation span Builder builder span class token operator 61 span span class token keyword
  • delete释放new[] 以及 delete[]释放new 的问题

    在同花顺 的笔试过程中遇到这么一个类似问题 A ptr 61 new A 10 for int i 61 0 i lt n i 43 43 delete amp ptr i 由此衍生出两个问题 new 申请的空间用delete释放会发生什么