首页 > 编程语言 >C++中delete和delete[]的深层区别

C++中delete和delete[]的深层区别

时间:2023-07-25 22:23:19浏览次数:37  
标签:调用 函数 元素 C++ 深层 析构 new delete

C++中delete和delete[]的深层区别

今天又看到群里有人讨论 C++deletedelete[]的区别,表层原因大家都了解,因为教科书上说得很明白:newdelete需配对使用, new[]delete[]需配对使用。

但若问起在什么情况下针对 new[]申请的资源可以使用 delete释放而不会有任何问题,能讲清楚这点的人就很少了。因为这涉及到对 newdeletenew[]delete[]内部实现机制的理解。

根本原因在于, delete需要调用内存中一个元素的析构函数,而 delete[]需要调用内存中若干个元素的析构函数,这里就牵涉出一个问题—— delete[]是如何知道内存中元素的数量的?我们知道 delete[]中的 []并不会传入参数,所以这个数量不会是 delete[]传过来的,而是在 new[]的时候保存的,只有这样才得以在 delete[]的时候依据元素数量逐个调用析构函数。

接下来说 new[]如何存储这个数量,首先它会动态申请一段内存,然后在这段内存的首地址空间中存入元素数量,在这个空间之后的内存分配给各元素,new[]的返回值并不是这段动态内存空间的首地址,而是动态内存空间中存放第一个元素的内存地址。

以上说的是 delete[]需要调用元素析构函数的情况,但是C++的哲学是 Zero-cost Abstraction,所以对于并没有显式定义析构函数的 struct/class的对象元素来说,并不需要为其产生析构函数的代码,也就不需要在 delete[]的时候调用元素的析构函数以增加无谓的运算开销,那么, new[]也就不用存储这个元素数量。还有一种情况就是如 int等基本类型作为空间元素的时候,也不存在析构函数的调用,所以跟没有显示定义析构函数的对象元素一样:在 new[]时候不需要存储元素数量,在 delete[]时候不需要调用析构函数。

综上所述, new[]delete[]的具体行为受对象元素是否存在必须调用析构函数而有所不同。

一图胜千言,我画了三张图来展现上面说的三种元素情况:

  • int作为基本类型:

int *ptr = new int[5]

  • 定义了一个 class A,但是 A并没有显式定义析构函数:

A *ptr = new A[5]

  • 定义了一个 class B,并且 B显式定义了析构函数:

B *ptr = new B[5]

可以看出,对于 int *ptr = new int[5]A *ptr = new A[5],因为不涉及存储元素数量和对析构函数的调用,所以 deletedelete[]的操作都仅仅是将传入的地址进行释放而不做其他额外事情。这种情况下,你使用 delete或者 delete[]都不会存在任何问题。

但是对于 B *ptr = new B[5]却一定要使用 delete[],因为传过来的并不是真正的动态内存首地址, delete[]的内部处理就会变成从传入的内存地址往前偏移获取真正的动态内存首地址,从该首地址空间获取到元素的数量,然后通过数量逐个调用元素的析构函数,完了再用得到的内存首地址释放动态内存。但若使用 delete就会只调用第一个元素的析构函数,并且将第一个元素的地址作为动态内存首地址进行释放,但是释放错误的内存地址(非申请时候动态内存的首地址)将发生严重错误,如在 visual studio 中会直接触发程序异常并崩溃。

接下来思考另一种情况,如果 B *ptr = new B操作后使用 delete[]释放呢?这也会产生非常严重的错误,因为它会根据这个内存地址往前偏移获取数量,但是这个数量值是个不确定的值,所以接下来发生的行为就是在指针越界访问的情况下调用了无数次析构函数,而这些内存空间中并不存在有效元素,该行为将发生程序崩溃,即便该过程程序照常执行,接下来用偏移地址释放内存也会崩溃,总之,程序执行到此已经走火入魔了。

标签:调用,函数,元素,C++,深层,析构,new,delete
From: https://www.cnblogs.com/bigbeet/p/17581208.html

相关文章

  • C++ 单例模式三种写法
    #include<iostream>#include"Apple.h"#include"Singleton.h"#include"ActivityManager.h"#include"ResourceManager.h"usingnamespaceMySpace;intmain(){Apple::abc=10;//参考:https://blog.csdn.n......
  • Eclipse for c/c++ 导入外面项目没有信息打印出来
      eclipseforc/c++ 导入外面项目没有信息打印出来: 就是因为这个Binaries里面二进制文件太多了,不知道运行哪一个,造成无输出,全删或只保留一个再编译运行: 运行成功:thevalueofsin(2.0)is0.909297TheIDofthisthreadis:-1202372520155============gett......
  • python使用ctypes调用gcc编译的dll之g++编译c++代码
    1、在windows系统将cpp代码编译成可供python调用的dll1.1新建header.h代码如下#pragmaonce#defineDllExport__declspec(dllexport)extern"C"{DllExportvoidhello_world(void);}/*#pragmaonce用来防止某个头文件被多次include,这条指令就能够保证头文件被......
  • [c/c++][考研复习笔记]内部排序篇学习笔记
    考研排序复习笔记插入排序#include<stdio.h>#include<stdlib.h>#defineMaxSize9//折半插入排序voidZBInsertSort(intA[],intn){ inti,j,high,low,mid; for(i=2;i<=n;i++){ A[0]=A[i]; low=1;high=i-1; while(low<=high){ mid=(low+high)/2......
  • C++强大、高性能、易于使用的format库
     fmtlib/fmt:Amodernformattinglibrary(github.com) {fmt} isanopen-sourceformattinglibraryprovidingafastandsafealternativetoCstdioandC++iostreams. DocumentationCheatSheetsQ&A:askquestionson StackOverflowwiththetagfmt.......
  • C++20 Ranges简述
    C++20引入了范围(Ranges)的新特性,这是一种现代化的、功能强大的处理序列数据的机制。范围(Ranges)的目标是提供一种更简洁、更易读、更安全且更高效的方式来操作数据序列,代替传统的迭代器和手动循环操作。这里是C++20Ranges的一些详细解释:范围概念:范围(Ranges)是一种统一的序......
  • C++中定义一个二维数组
    在C++中定义二维数组有很多种方式1.第一种方式:定义一个二级指针(指向指针的指针)#include<iostream>usingnamespacestd;voidTraverse(int**p);intmain(){//two-dimensionarrayintm=3,n=5;int**arr=newint*[m];arr[0]=newint[n];arr[1......
  • C++11 可平凡复制类型 (TriviallyCopyable)
    可平凡复制类型标量类型(算数类型/枚举/指针)可平凡复制类类型可平凡复制类型的数组cv限定的可平凡复制类型(const/volatile)TriviallycopyableclassAtriviallycopyableclassisaclassthathasatleastoneeligiblecopyconstructor,moveconstructor,copyassi......
  • Code-OpenSource-JSON for Modern C++ v3.10.5
    Code-OpenSource-JSONforModernC++v3.10.5github.com/nlohmann/jsonhttps://json.nlohmann.me/home/exceptions/#version-historyhttps://json.nlohmann.me/api/macros/json_diagnostics/#extended-diagnostic-messages#defineJSON_DIAGNOSTICS1输出详细信息......
  • c++学习经验总结
    1.关于结构体中定义函数在C++中,结构体中定义函数没问题在C中,则不行。会报expectedspecifier-qualifier-listbefore...2.在C++中,结构体与类的区别:在C++中,结构体是一种特殊形态的类。结构体和类的唯一区别就是:结构体和类具有不同的默认访问控制属性。3.C与C++中结构体......