6

可能重复:
(POD)释放内存:delete[] 等于 delete 吗?

是否delete释放数组中第一个元素之外的元素?

char *s = new char[n];
delete s;

在上述情况下,看到 的所有元素s都是连续分配的,不应该delete只分配数组的一部分吗?

对于更复杂的类型,是否会delete调用第一个之外的对象的析构函数?

Object *p = new Object[n];
delete p;

怎么能delete[]推导出Object第一个之外的 s 的数量,这不是说它必须知道分配的内存区域的大小吗?如果出于性能原因分配的内存区域有一些悬垂怎么办?例如,可以假设并非所有分配器都提供单个字节的粒度。那么任何特定的分配都可能超过每个元素所需的大小一个或更多的整个元素。

对于原始类型,例如char, int,两者之间有什么区别:

int *p = new int[n];
delete p;
delete[] p;
free p;

delete除了通过->free释放机制的各个调用所采用的路由吗?

4

10 回答 10

16

这是未定义的行为(很可能会立即损坏堆或使程序崩溃),您永远不应该这样做。仅释放具有与用于分配该内存的原语相对应的原语的内存。

违反此规则可能会碰巧导致正常运行,但一旦更改任何内容(编译器、运行时、编译器设置),程序就会中断。你永远不应该依赖这种正常的功能并期待它。

delete[]使用特定于编译器的服务数据来确定元素的数量。通常在被调用时分配一个更大的块new[],数字存储在开头,调用者被赋予存储数字后面的地址。无论如何delete[],依赖于由 分配的块new[],而不是其他任何东西。如果您将任何东西配对new[]delete[]反之亦然,您会遇到未定义的行为。

于 2009-10-23T08:19:13.523 回答
10

阅读常见问题解答:16.3 我可以用 new 分配 free() 指针吗?我可以删除用 malloc() 分配的指针吗?

在上述情况下,看到 s 的所有元素都是连续分配的,并且不应该只删除数组的一部分,这是否重要?

是的,它确实。

delete[] 如何推断出第一个之外的对象数量,这是否意味着它必须知道分配的内存区域的大小?

编译器需要知道。请参阅常见问题解答 16.11

因为编译器存储了这些信息。

我的意思是编译器需要不同delete的 s 来生成适当的簿记代码。我希望这现在很清楚。

于 2009-10-23T08:19:17.813 回答
4

是的,这很危险!

不要这样做!

这将导致程序崩溃甚至更糟糕的行为!

对于分配给new您的对象,必须使用delete;

对于分配给new []您的对象,必须使用delete [];

对于分配的对象,malloc()或者calloc()必须使用free();

另请注意,对于所有这些情况,再次删除/释放已删除/释放的指针是非法的。free也不能用 null 调用。使用 NULL调用delete/delete[]是合法的。

于 2009-10-23T08:30:51.707 回答
3

是的,有一个真正的实际危险。即使是实现细节,请记住,operator new/operator delete函数operator new[]/operator delete[]可以完全独立地替换。出于这个原因,明智的做法是将new/delete,new[]/delete[]malloc/free视为不同的、完全独立的内存分配方法,它们完全没有任何共同点。

于 2009-10-23T08:47:06.867 回答
2

delete 是否会释放数组中第一个元素之外的元素?

不,无论您执行哪个编译器,delete 都只会释放第一个元素。在某些情况下它可能会起作用,但这是偶然的。

在上述情况下,看到 s 的所有元素都是连续分配的,并且不应该只删除数组的一部分,这是否重要?

取决于内存如何标记为空闲。再次依赖于实现。

对于更复杂的类型,delete 会调用第一个之外的对象的析构函数吗?

不,试试这个:

#include <cstdio>

class DelTest {
    static int next;
    int i;
public:
    DelTest() : i(next++) { printf("Allocated %d\n", i); }
    ~DelTest(){ printf("Deleted %d\n", i); }
};

int DelTest::next = 0;

int main(){
    DelTest *p = new DelTest[5];
    delete p;
    return 0;
}

delete[] 如何推断出第一个之外的对象数量,这是否意味着它必须知道分配的内存区域的大小?

是的,大小存储在某个地方。它的存储位置取决于实现。例如,分配器可以将大小存储在分配地址之前的标头中。

如果出于性能原因分配的内存区域有一些悬垂怎么办?例如,可以假设并非所有分配器都提供单个字节的粒度。那么任何特定的分配都可能超过每个元素所需的大小一个或更多的整个元素。

正是由于这个原因,返回的地址与字边界对齐。使用 sizeof 运算符可以看到“悬垂”,也适用于堆栈上的对象。

对于原始类型,例如 char、int,...之间有什么区别吗?

是的。malloc 和 new 可以使用单独的内存块。即使不是这种情况,最好不要假设它们是相同的。

于 2009-10-23T08:54:31.923 回答
2

Raymond Chen(Microsoft 开发人员)有一篇深入的文章,涵盖缩放器与矢量删除,并提供了一些差异的背景。看:

http://blogs.msdn.com/oldnewthing/archive/2004/02/03/66660.aspx

于 2009-10-23T13:43:38.553 回答
1

对于原始类型,例如 char、int,两者之间有什么区别:

我会说你会得到未定义的行为。所以你不应该指望稳定的行为。您应该始终使用 new/delete、new[]/delete[] 和 malloc/free 对。

于 2009-10-23T08:17:35.353 回答
1

这是未定义的行为。因此,答案是:是的,可能存在危险。而且不可能准确预测什么会引发问题。就算一次有效,还会再有效吗?这取决于类型吗?元素计数?

于 2009-10-23T08:17:58.567 回答
0

尽管从某种逻辑上看,您可以混合使用 new[] 和 free 或 delete 而不是 delete[],但这是假设编译器相当简单,即它总是使用 malloc() 来实现new[] 的内存分配。

问题是,如果您的编译器有一个足够聪明的优化器,它可能会看到没有与您创建的对象的 new[] 对应的“delete[]”。因此它可能假设它可以从任何地方获取内存,包括堆栈,以节省为 new[] 调用真正的 malloc() 的成本。然后,当您尝试对其调用 free() 或错误类型的 delete 时,它​​很可能会出现故障。

于 2009-10-23T08:48:27.053 回答
0

第 1 步阅读:what-is-the-difference-between-new-delete-and-malloc-free

您只是在查看您在开发人员方面看到的内容。
您没有考虑的是标准库如何进行内存管理。

第一个区别是 new 和 malloc 从内存中的两个不同区域分配内存(来自 FreeStore 的 New 和来自 Heap 的 malloc (不要关注它们基本上都是堆的名称,那些只是标准中的官方名称)。如果您从一个分配并取消分配到另一个,您将弄乱用于管理内存的数据结构(没有保证他们将使用相同的结构进行内存管理)。

当您分配这样的块时:

int*   x= new int; // 0x32

记忆可能看起来像这样:它可能不会,因为我没有那么努力地编造了这个。

Memory   Value      Comment
0x08     0x40       // Chunk Size  
0x16     0x10000008 // Free list for Chunk size 40
0x24     0x08       // Block Size
0x32     ??         // Address returned by New.
0x40     0x08       // Pointer back to head block.
0x48     0x0x32     // Link to next item in a chain of somthing.

关键是分配的块中的信息比分配用于处理内存管理的 int 多得多。

该标准没有具体说明这是如何完成的,因为(以 C/C++ 风格)他们不想影响编译器/库制造商为该架构实现最有效的内存管理方法的能力。

考虑到这一点,您希望制造商能够将数组分配/解除分配与正常分配/解除分配区分开来,以便使其对两种类型都尽可能有效。因此,您不能在内部混合和匹配,因为它们可能使用不同的数据结构。

如果您实际分析 C 和 C++ 应用程序之间的内存分配差异,您会发现它们非常不同。因此,使用完全不同的内存管理技术来优化应用程序类型并不是不合理的。这是在 C++ 中更喜欢 new 而不是 malloc() 的另一个原因,因为它可能会更有效(尽管更重要的原因始终是降低复杂性(IMO))。

于 2009-10-23T19:28:38.903 回答