2011-08-05 63 views
4

可能重复:
How could pairing new[] with delete possibly lead to memory leak only?
(POD)freeing memory : is delete[] equal to delete?删除数组时删除和删除[]是否一样?

使用GCC 4.1.2版20080704(红帽4.1.2-48)。没有在Visual C++上测试过它。

看起来deletedelete []在删除“简单”类型的数组时相同。

char * a = new char[1024]; 
delete [] a; // the correct way. no memory leak. 

char * a = new char[1024]; 
delete a; // the incorrect way. also NO memory leak. 

但是,在删除“复杂”类型的数组时,delete会导致内存泄漏。

class A 
{ 
public: 
    int m1; 
    int* m2; // a pointer! 
    A() 
    { 
     m2 = new int[1024]; 
    } 
    ~A() 
    { 
     delete [] m2; // destructor won't be called when using delete 
    } 
}; 
A* a = new A[1024]; 
delete [] a; // the correct way. no memory leak. 

A* a = new A[1024]; 
delete a; // the incorrect way. MEMORY LEAK!!! 

我的问题是:

  1. 在第一次测试的情况下,为什么deletedelete []正在得到的相同++?
  2. 在第二个测试用例中,为什么g ++不像第一个测试用例那样处理它?
+0

您是如何确认在第一种情况下没有内存泄漏并且在这两种情况下都没有内存错误? – neuront

+0

请仔细阅读这个问题 - http://stackoverflow.com/q/1913343/57428其中详细解释了所有原因。 – sharptooth

+1

就内存释放而言,它可能会像第一种情况一样处理它。在这两种情况下,总分配大小通常以相同的方式存储,所以内存得到正确释放。 但是,delete []被设计为为每个分配的对象调用析构函数,而delete只会在第一个对象上调用它,即a [0]。 这就是内存泄漏发生的原因。 A对象内部的int数组未被释放,因为析构函数未被调用,但A对象的初始分配被正确释放。 无论哪种方式,这是不可移植的未定义的行为。 –

回答

1

因为这是未定义的行为。它不保证可以中断,但也不能保证可以正常工作。

0

它们在技术上并不相同,它们只是在非复杂类型上进行了相同的优化。复杂类型需要矢量化delete,以便可以为您的delete阵列中的每个对象调用析构函数(就像构造函数的矢量化new一样)。

你在做什么只是释放像它的指针数组一样的内存。

6
char * a = new char[1024]; 
delete a; // the incorrect way. also NO memory leak. 

不,它不包括No memory leak。它实际上调用了未定义的行为。

9

这完全依赖于底层的内存管理器。简而言之,C++要求您删除delete[]的数组,并使用delete删除非数组。标准中没有解释你的行为。

但是,可能发生的情况是delete p;只是从p(无论是否为数组)开始释放内存块。另一方面,delete[]另外遍历数组的每个元素并调用析构函数。由于像char这样的正常数据类型没有析构函数,因此没有影响,因此deletedelete[]最终会做同样的事情。

就像我说的,这是所有的具体实现。不能保证delete可以用于任何类型的阵列。它恰好适用于你的情况。在C++中,我们称之为未定义的行为 - 它可能工作,它可能不会,它可能会做一些完全随机的和意想不到的事情。你最好避免依赖未定义的行为。

1

删除表达式在释放内存之前调用要删除的对象的析构函数。释放内存可能适用于任何情况(但仍然是UB),但如果您使用delete(需要delete[]),则不会调用所有析构函数。由于你的复杂对象本身分配了内存,并在它自己的析构函数中释放它,所以当你使用错误的表达式时,你无法完成所有这些删除操作。

3

delete and delete[]在g ++中表面上看起来相当于纯粹的运气。在拨号为new[]的内存上调用delete,反之亦然,是未定义的行为。只是不要这样做。

0

这里发生的事情是,当您调用delete时,对象占用的空间将被删除。在字符的情况下,这就是你所需要做的(虽然仍然推荐使用delete [],因为这只是g ++。调用数组的delete的实际行为在C++标准中是未定义的)。

在第二个例子中,数组占用的空间被释放,包括指针m2。但是,m2指向的内容不会被删除。当您调用delete []时,将调用数组中每个对象的析构函数,然后解除分配m2指向的内容。