delete与delete[]的区别

来源:互联网 发布:yy加好友软件 编辑:程序博客网 时间:2024/05/22 11:59
delete与delete[]的区别

由new分配的一个数组空间,比如说 int *array=new int[50],当用delete释放这个空间时,用语句delete []array和delete array是否等价!


C++告诉我们在回收用 new 分配的单个对象的内存空间的时候用 delete,回收用 new[] 分配的一组对象的内存空间的时候用 delete[]。

关于 new[] 和 delete[],其中又分为两种情况:(1) 为基本数据类型分配和回收空间;(2) 为自定义类型分配和回收空间。

对于 (1),上面提供的程序a可以证明了 delete[] 和 delete 是等同的。
程序a:
#include <stdio.h>
#define BUFF_SIZE 10240
int main(int argc, char *argv[])
{
printf("Hello, world\n";
char* p = NULL;
while(1)
{
p = new TTT[BUFF_SIZE];
printf("0x%08XH\n",p);
Sleep(5000);
delete p; //或者delete [] p;
p = NULL;
}
return 0;
}

但是对于 (2),情况就发生了变化。请看下面的程序。
#include <stdio.h>
#define BUFF_SIZE 10240

class TTT
{
public:
TTT()
{
//aa = new char[1024];
};
~TTT()
{
//delete [] aa;
//printf("TTT destructor()\n";
};
private:
int a;
char* aa;
int inta[1024];
};

int main(int argc, char *argv[])
{
printf("Hello, world\n";
TTT* p = NULL;
while(1)
{
p = new TTT[BUFF_SIZE];
printf("0x%08XH\n",p);
delete p; //delete [] p;
p = NULL;
}
return 0;
}

大家可以自己运行这个程序,看一看 delete p1 和 delete[] p1 的不同结果,我就不在这里贴运行结果了。

从运行结果中我们可以看出,delete p 在回收空间的过程中,只有 p[0] 这个对象调用了析构函数,其它对象如 p[1]、p[2] 等都没有调用自身的析构函数,在析构函数中的内存释放操作将不会被执行(引发内存泄漏),已使用内存不断增加,这就是问题的症结所在。如果用 delete[],则在回收空间之前所有对象都会首先调用自己的析构函数,已使用内存不会不断增加。

基本类型的对象没有析构函数,所以回收基本类型组成的数组空间用 delete 和 delete[] 都是应该可以的;但是对于类对象数组,只能用 delete[]。对于 new 的单个对象,只能用 delete 不能用 delete[] 回收空间。
所以一个简单的使用原则就是:new 和 delete、new[] 和 delete[] 对应使用。

//
delete 和delete[] 只是告诉编译器这个地址的内容已经被释放了,该地址又是重新可用的了,我们常说的野指针就是delete 和delete[]后的地址,正确的做法是在delete 后把该指针赋为null
参考资料:http://dev.csdn.net/develop/article/38/38316.shtm


作者后续相关文章:


昨天写了一篇关于delete和delete[]的文章,有位仁兄指出我的结论是错误的,那样的结果只会在特定的编译器程序。为了不会误导大家,文章意见删除。回家后仔细看了《Effective C++》,是我看书太不仔细了,虽然忘了那位仁兄是谁了,在这里还是谢谢你。现将《Effective C++》中正确的观点、结论摘录如下:

1.              当你使用new时,有两件事会发生。第一,内存被配置(透过函数operator new)。第二,会有一个(或以上)的constructors针对此内存被调用。当你使用delete时,也有两件事发生:一个(或以上)的destructors会针对此内存被调用,然后内存被释放(透过函数operator delete)。

2.              如果你使用delete是未加括号,delete便假设删除对象是单一对象。否则便假设删除对象是个数组。

3.              string *stringPtr1 = new string;

string *stringPtr2 = new string[100];

……

delete stringPtr1;

delete [] stringPtr2;

如果你对着stringPtr1使用“[]”形式,其结果未定义。如果你对着stringPtr2没有使用“[]”形式,其结果亦未定义。犹有进者,这对内建型别如int者亦未定义,即使这类型别并没有destructors。

4.              因此,游戏规则很简单,如果你在调用new时使用了[],则你在调用delete时也使用[],如果你在调用new的时候没有[],那么你也不应该在调用时使用[]。


//
发现有人在问C++中的delete和delete[]的使用方法,为了方便新手学习,写了这篇文章,大家可以看看,我们一来看下面的例子,通过例子的学习了解C++中的delete和delete[]的使用方法

#include <iostream>
using namespace std;
/////////class Babe
class Babe
{
public:
    Babe()
    {
        cout << \"Create a Babe to talk with me\" << endl;
    }
    ~Babe()
    {
        cout << \"Babe don\'t go away,listen to me\" << endl;
    }
};
//////////main function
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来释放也许不会出问题,也许后果很严重,具体要看类的代码了。[Page]


//
一个关于c++字符串处理和delete[]与delete差别的问题
                                                                       ---张吕全

先看下面一个字符串处理的小例子
 CString str = "zhongguo";//在c++builder中CString 对应的类型AnsiString 其余一样
 CString strtwo = str;//值拷贝
 int *addr = (int*)&strtwo;
 char*p = (char*)*addr;
 *p = 'X';
 AfxMessageBox(str);//cb中为  ShowMessage(str);
      这时大家可以发现strtwo变成了Xhongguo这是正常的,然而再看str 却也变成了它。显然两者都是指向共同的数据区。原来,在vc和c++Builder中在处理字符串时,都进行了优化。当进行赋值操作时,并不进行真正的数据拷贝操作。而是使二者指向相同的数据区而已,并将该内存块的引用数加一。当对字符串单个操作等可能破坏其他用户的数据操作时,才检查它的引用数,以决定是否要拷贝一份数据。具体详细操作,要涉及c++Builder和 vc编译器的各自的内存管理方式了。其实这种处理技巧在许多地方随处可见。如动态链接库的调用,以及COM对象的实现等等。
    还有一个是关于对数组进行delete和delete[]的差别,我认为至少在vc6.0和c++Builder5.0中(其它版本我也没有用过!),它们这两个操作时没有区别的,例如:
    char * p= new char[100000];
    //。。。它操作
    delete p;// 和 delete p[]是等价的
我通过代码分析和例子测试两种途径,证实两者是一样的,然而我见到的所有资料上介绍都是说它们是不一样的,或许他们说的是c++标准规定,我也没有空去核查过,嘻嘻,毕竟饭碗要紧!
    抛开代码分析,可以做个简单的测试。分别放两个按钮。处理代码如下:
一:
       for (int i = 0 ; i < 100000 ; i++)
    {
        char * p= new char[100000];
        delete p;
    }
二:
    for (int i = 0 ; i < 100000 ; i++)
    {
        char * p= new char[100000];
        delete p[];
    }
分别按下测试,可以通过任务管理器(或其他工具软件)两者的内存增加是一样的(可能是4k),这是在第一次new时系统分配的内存。这是windows内存分配委托所致的假象。都进行了内存释放!在vc下可以用CMemoryState类进行检测更方便,具体可以查看相关的msdn资料了。顺便说一下,由于vc在释放内存时,还要进行内存块清零等操作,所以在速度上远不及c++builder,就是发行版也还是无法和cb的调试版相媲美的。




//
delete与delete []
delete与delete []是时c++内置类型(int ,double ,float……)时二者是没有任何区别的,都能够释放掉生成的内存空间,但是当是自定义的类型的时候,特别是自定义的class,当使用delete时不会调用所有元素的析构函数。

//============================================================================
// Name        : DeleteTest.cpp
// Author      : Arinic
// Version     :
// Copyright   : IPRAI
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
using namespace std;
class Base
{
public:
    Base(){}
    ~Base(){cout << "Base destroy!" << endl;}
};

int main()
{
    Base *pBase = new Base[4];
    delete [] pBase;
    return 0;
}
当使用delete时析构函数只会被调用一次,而使用delete []会调用四次!