delete 和 delete [] 的真正区别

时间:2022-07-28
本文章向大家介绍delete 和 delete [] 的真正区别,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

来源:cbNotes 链接:http://blog.csdn.net/cbnotes/article/details/38900799

来源:公众号(c语言与cpp编程)

c++ 中对new 申请的内存的释放方式有 deletedelete[] 两种方式,到底这两者有什么区别呢?

我们通常从教科书上看到这样的说明:

  • delete 释放new分配的单个对象指针指向的内存
  • delete[] 释放new分配的对象数组指针指向的内存

那么,按照教科书的理解,我们看下下面的代码:

int *a = new int[10];
delete a;        //方式1
delete[] a;     //方式2

1. 针对简单类型 使用new分配后的不管是数组还是非数组形式内存空间用两种方式均可 如:

int *a = new int[10];
delete a;
delete[] a;

此种情况中的释放效果相同,原因在于:分配简单类型内存时,内存大小已经确定,系统可以记忆并且进行管理,在析构时,系统并不会调用析构函数。

它直接通过指针可以获取实际分配的内存空间,哪怕是一个数组内存空间(在分配过程中 系统会记录分配内存的大小等信息,此信息保存在结构体 _CrtMemBlockHeader 中,具体情况可参看 VC 安装目录下 CRTSRCDBGDEL.cpp)。

2. 针对类Class,两种方式体现出具体差异

当你通过下列方式分配一个类对象数组:

class A
   {
    private:
      char *m_cBuffer;
      int m_nLen;

   `` public:
      A(){ m_cBuffer = new char[m_nLen]; }
      ~A() { delete [] m_cBuffer; }
   };

   A *a = new A[10];
   delete a;         //仅释放了a指针指向的全部内存空间 但是只调用了a[0]对象的析构函数 剩下的从a[1]到a[9]这9个用户自行分配的m_cBuffer对应内存空间将不能释放 从而造成内存泄漏
   delete[] a;      //调用使用类对象的析构函数释放用户自己分配内存空间并且   释放了a指针指向的全部内存空间

所以总结下就是,如果 ptr 代表一个用new申请的内存返回的内存空间地址,即所谓的指针,那么:

delete ptr  代表用来释放内存,且只用来释放 ptr 指向的内存。delete[] rg   用来释放rg指向的内存,!!还逐一调用数组中每个对象的destructor!!

对于像int/char/long/int*/struct等等简单数据类型,由于对象没有 destructor ,所以用 deletedelete []是一样的!但是如果是 C++ 对象数组就不同了!

关于 new[]delete[],其中又分为两种情况:

  • (1)为基本数据类型分配和回收空间;
  • (2)为自定义类型分配和回收空间;

对于 (1),上面提供的程序已经证明了delete[]delete 是等同的。但是对于 (2),情况就发生了变化。

我们来看下面的例子,通过例子的学习了解 C++ 中的 deletedelete[] 的使用方法

#include <iostream>
using namespace std;

class Babe
{
public:
    Babe()
    {
        cout << "Create a Babe to talk with me" << endl;
    }

    ~Babe()
    {
        cout << "Babe don't Go away,listen to me" << endl;
    }
};

int main()
{
    Babe* pbabe = new Babe[3];
    delete pbabe;
    pbabe = new Babe[3];
    delete[] pbabe;
    return 0;
}

结果是:

Create a babe to talk with me
Create a babe to talk with me
Create a babe to talk with me
Babe don't go away,listen to me
Create a babe to talk with me
Create a babe to talk with me
Create a babe to talk with me
Babe don't go away,listen to me
Babe don't go away,listen to me
Babe don't go away,listen to me

大家都看到了,只使用 delete 的时候只出现一个 Babe don’t go away,listen to me,而使用 delete[] 的时候出现 3 个 Babe don’t go away,listen to me。不过不管使用 delete 还是 delete[] 那三个对象的在内存中都被删除,既存储位置都标记为可写,但是使用 delete 的时候只调用了 pbabe[0] 的析构函数,而使用了 delete[] 则调用了 3 个 Babe 对象的析构函数。

你一定会问,反正不管怎样都是把存储空间释放了,有什么区别。

答:关键在于调用析构函数上。此程序的类没有使用操作系统的系统资源(比如:Socket、File、Thread等),所以不会造成明显恶果。如果你的类使用了操作系统资源,单纯把类的对象从内存中删除是不妥当的,因为没有调用对象的析构函数会导致系统资源不被释放,如果是 Socket 则会造成 Socket 资源不被释放,最明显的就是端口号不被释放,系统最大的端口号是 65535 (216 _ 1,因为还有0),如果端口号被占用了,你就不能上网了,呵呵。如果 File 资源不被释放,你就永远不能修改这个文件,甚至不能读这个文件(除非注销或重启系统)。如果线程不被释放,这它总在后台运行,浪费内存和 CPU 资源。这些资源的释放必须依靠这些类的析构函数。所以,在用这些类生成对象数组的时候,用 delete[] 来释放它们才是王道。而用 delete 来释放也许不会出问题,也许后果很严重,具体要看类的代码了。