将new[]与delete配对怎么可能只导致内存泄漏? 首先,使用删除>代码>分配给新[]/COD>是根据C++标准的未定义行为。< /P> 在Visual C++ 7中,这样的配对可能导致两种后果之一。

将new[]与delete配对怎么可能只导致内存泄漏? 首先,使用删除>代码>分配给新[]/COD>是根据C++标准的未定义行为。< /P> 在Visual C++ 7中,这样的配对可能导致两种后果之一。,c++,memory-management,undefined-behavior,C++,Memory Management,Undefined Behavior,如果new[]'ed类型具有普通的构造函数和析构函数,VC++只需使用new而不是new[],并且对该块使用delete效果良好-new只需调用“分配内存”,delete只需调用“空闲内存” 如果new[]'ed类型有一个非平凡的构造函数或析构函数,那么上述技巧就无法实现——VC++7必须调用正确数量的析构函数。因此,它使用存储元素数量的size\u t作为数组的前缀。现在,new[]返回的地址指向第一个元素,而不是块的开头。因此,如果使用delete,它只调用第一个元素的析构函数,并调用“fr

如果new[]'ed类型具有普通的构造函数和析构函数,VC++只需使用
new
而不是
new[]
,并且对该块使用
delete
效果良好-
new
只需调用“分配内存”,
delete
只需调用“空闲内存”

如果new[]'ed类型有一个非平凡的构造函数或析构函数,那么上述技巧就无法实现——VC++7必须调用正确数量的析构函数。因此,它使用存储元素数量的
size\u t
作为数组的前缀。现在,
new[]
返回的地址指向第一个元素,而不是块的开头。因此,如果使用
delete
,它只调用第一个元素的析构函数,并调用“free memory”,其地址与“allocate memory”返回的地址不同,这会导致HeapFree()中出现一些错误指示,我怀疑这是指堆损坏

然而,到处都可以看到错误的陈述,即在
new[]
之后使用
delete
会导致内存泄漏。我怀疑任何大小的堆损坏都比仅为第一个元素调用析构函数以及可能未调用的析构函数没有释放堆分配的子对象更重要


new[]之后如何使用
删除
可能只导致某些C++实现中的内存泄漏。

< P>如果在数组中的第一个元素没有调用所有非平凡的析构函数,则应该释放一些内存,因为这些对象没有被正确清理,就会出现内存泄漏。

< P>除了导致未定义的行为外,泄漏最直接的原因在于实现除了数组中的第一个对象之外,没有为所有对象调用析构函数。如果对象分配了资源,这显然会导致泄漏

这是我能想到的导致这种行为的最简单的类:

 struct A { 
       char* ch;
       A(): ch( new char ){}
       ~A(){ delete ch; }
    };

A* as = new A[10]; // ten times the A::ch pointer is allocated

delete as; // only one of the A::ch pointers is freed.

PS:注意,在很多其他编程错误中,构造函数也没有被调用:非虚基类析构函数,错误依赖智能指针,……/P>< P>在析构函数释放内存的任何情况下,都会导致C++的所有实现中出现泄漏,因为析构函数永远不会被调用。


在某些情况下,它会造成更严重的错误。

< P>假设我是C++编译器,我实现了这样的内存管理:我用字节的大小来准备每个内存块的大小。像这样的东西

| size | data ... |
         ^
         pointer returned by new and new[]
注意,在内存分配方面,
new
new[]
之间没有区别:两者都只分配一定大小的内存块

现在,
delete[]
如何知道数组的大小,以便调用正确数量的析构函数?只需将内存块的
size
除以
sizeof(T)
,其中
T
是数组的元素类型


现在假设我将
delete
实现为对析构函数的一次调用,然后释放
size
字节,那么后续元素的析构函数将永远不会被调用。这会导致后续元素分配的资源泄漏。但是,因为我释放了
size
字节(而不是
sizeof(T)
bytes),所以不会发生堆损坏。

如果覆盖了new()运算符,而没有覆盖new[],则可能会发生内存泄漏。delete/delete[]操作符也是如此,您的问题似乎是“为什么堆损坏不会发生?”。答案是“因为堆管理器跟踪分配的块大小”。让我们回到C一分钟:如果您想在C中分配一个int,您可以执行
int*p=malloc(sizeof(int))
,如果您想分配大小数组
n
,您可以编写
int*p=malloc(n*sizeof(int))
int*p=calloc(n,sizeof(int))
。但是在任何情况下,您都可以通过
free(p)
释放它,无论您如何分配它。您永远不会将size传递给free(),free()只“知道”要释放多少,因为malloc()-ed块的大小保存在块“前面”的某个位置。回到C++,Neal/Delphi和Neal[]/Dele[]通常以Maloc的形式实现(虽然它们不必是,但不应依赖于此)。这就是为什么new[]/delete组合不会损坏堆-delete将释放适当数量的内存,但是,正如我之前的每个人所解释的,如果调用的析构函数数量不正确,则可能会导致泄漏


<>这是说,C++中关于未定义行为的推理总是毫无意义的练习。如果new[]/delete组合碰巧起作用,“only”泄漏或导致堆损坏,这又有什么关系呢?你不应该那样编码,句号!而且,在实践中,我会尽可能避免手动内存管理—STL和boost的存在是有原因的。

关于混合
新[]
删除
的童话故事据称会导致内存泄漏,这只是一个童话故事。它在现实中根本没有立足之地。我不知道它是从哪里来的,但现在它已经有了自己的生命,并且像病毒一样存活下来,通过口碑从一个初学者传播到另一个初学者

这种“内存泄漏”胡说八道背后最可能的理由是,从天真的角度来看,
delete
delete[]
之间的区别在于
delete
只用于销毁一个对象,而
delete[]
则销毁一组对象(“许多”对象)。通常由此得出的一个简单结论是,数组的第一个元素将被
delete