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

int* p = new int[5]; int *p = new int[5]();delete[] p; delete p;区别是什么?

int main() {int *p = new int[5]; // 分配包含5个整数的数组内存// 初始化数组元素for (int i = 0; i < 5; i++) {p[i] = i * 10;}// 试图使用 delete p; 来释放数组内存delete p;delete[] p;// 打印数组元素for (int i = 0; i < 5; i++) {std::cout << "p[" << i << "] = " << p[i] << std::endl;}return 0;
}

代码如上,在delete p;的时候会发生什么问题,又是什么原因导致的?

首先,需要知道delete在底层都做了什么:

  1. 调用析构函数:如果 p 指向一个对象(而不是基本数据类型的数组),C++ 运行时将调用这个对象的析构函数。对于基本数据类型(如 int、float 等)或者数组,析构函数不会被调用,因为它们没有析构函数。

  2. 内存回收delete 操作将释放 p 指向的内存块。这块内存之后可能被操作系统回收,或者留待将来重新分配。

  3. 清理内部管理信息:C++ 运行时维护了一些内部数据结构来管理动态分配的内存。delete 操作将更新这些数据结构,标记相应的内存块为“可用”

而int *p = new int[5];中的p是指向该数组首地址的指针,如果你是用delete p;其实只是做了:

        1. 删除了p这个对象

        2. 回收p所指向内存(数组首个元素)

        3. 清理内部管理信息

所以,数组剩下的元素是没有被清理回收的,我用ide输出了结果,发现delete p的结果如下:

p[0] = 1490466881
p[1] = 5
p[2] = -720962155
p[3] = 305593618
p[4] = 40

都是一些奇怪的值,也能证明刚才提到的delete p所发生的的事情。

如果你分配了数组,要进行释放,使用delete[] p;  p = nullptr;如下:

int main() {int *p = new int[5]; // 分配包含5个整数的数组内存// 初始化数组元素for (int i = 0; i < 5; i++) {p[i] = i * 10;}delete[] p;p = nullptr;// 打印数组元素for (int i = 0; i < 5; i++) {std::cout << "p[" << i << "] = " << p[i] << std::endl;}return 0;
}

那delete[] p;底层实现是怎么做的呢?以下:

  1. 查找数组大小:运行时使用 p 指针回退到数组大小存储的位置,获取数组的大小。

  2. 调用析构函数:如果数组元素是类对象,并且有析构函数,运行时将为数组中的每个元素调用析构函数。运行时知道数组的大小,所以它可以正确地循环通过每个元素来调用析构函数。

  3. 内存回收:运行时释放整个数组占用的内存块,包括存储数组大小的那部分内存。

  4. 清理内部管理信息:运行时更新其内部数据结构,标记相应的内存块为“可用”。

那代码中还有一个问题,我们一般new会调用构造函数,代码如下:

int *p = new int[5]; 
int *p = new int[5](); 

以上两个有什么区别呢?简单来说:

  1. int *p = new int[5];

    • 不会初始化数组中的元素。拥有未定义的值,取决于内存初始状态。
    • 必须在使用数组之前手动初始化每个元素。
  2. int *p = new int[5]();

    • 会将数组中的每个元素初始化为0。
    • “值初始化”(value-initialization)。当你在 new 表达式后面加上一对空括号 () 时,触发值初始化。对于基本数据类型如 int,初始化为0。
    • 确保数组的每个元素都被初始化为一个确定的值,减少了出错。

大概是这些~,有帮助就点个赞吧!

http://www.lryc.cn/news/214410.html

相关文章:

  • 数据结构|基础知识定义
  • 物联网AI MicroPython传感器学习 之 MFRC522 RFID射频IC卡感应模块
  • 搭建ES集群
  • Tomcat的日志接收文件catalina.out nohup.out说明
  • 手机ip地址切换后有什么影响
  • C++ 赋值运算重载,const成员,取地址及const取地址操作符重载
  • 嵌入式Linux系统的闪存设备和文件系统学习纪要
  • android 8.1 disable unsupported sensor
  • 二、类与对象(一)
  • 写给所有的程序员,或者努力生活的你。
  • pytorch 笔记:GRU
  • Kubernetes - Ingress HTTP 升级 HTTPS 配置解决方案(新版本v1.21+)
  • Verilog:写流水灯时遇到的问题
  • 操作系统第四章-存储器管理
  • org.springframework.cloud:spring-cloud-starter-openfeign:jar is missing详解
  • Netty第一部
  • 【设计模式】第11节:结构型模式之“装饰器模式”
  • Spire.doc读取模板文档,并在书签处插入内容
  • 性能测试实施流程,5个阶段给老板安排的明明白白!
  • 【教程】R语言生物群落(生态)数据统计分析与绘图
  • 数据库-用户权限管理
  • 十一、W5100S/W5500+RP2040树莓派Pico<ARP 地址解析>
  • 可以直接在线制作电子画册的网站
  • SortableJS:vuedraggable实现元素拖放排序
  • 跟着Nature Communications学作图:纹理柱状图+添加显著性标签!
  • 88. 合并两个有序数组、Leetcode的Python实现
  • 视频列表:点击某个视频进行播放,其余视频全部暂停(同时只播放一个视频)
  • 论文-分布式-共识,事务以及两阶段提交的历史描述
  • [100天算法】-二叉树剪枝(day 48)
  • 常用编程语言排行与应用场景汇总(2023.10)