【问题标题】:Why does the regular delete operator work when the array delete operator should be required?当需要数组删除运算符时,为什么常规删除运算符起作用?
【发布时间】:2013-02-03 19:57:42
【问题描述】:

我最近发现我们代码中的很多地方都在做这样的事情:

int * int_array = new int[1000];

// ... do things with int_array

delete int_array;

问题当然是它应该使用delete [] 运算符,而不是常规的delete 运算符。

谜团在于:这段代码在 Windows 上由 Visual Studio 2003 和 2005 编译,在 OS X 上由 GCC/clang 编译时,已经运行了好几年。为什么这之前没有导致事情出现严重错误?

据我了解,我们告诉编译器以“错误”的方式释放内存,通常如果你这样做,会发生可怕的事情并且你的程序崩溃。为什么这不会发生在我们身上?现代编译器是否会自动为您“做正确的事情”,或者是否足够正确的事情对基本类型无关紧要,或者其他什么?我不能接受我们只是运气好,因为这段代码已经使用了多年,在多个不同的操作系统下被成千上万的客户使用。

请注意,我并不是在为做错事找借口,只是想了解为什么我们不会因为做错事而陷入困境。 :)

【问题讨论】:

  • 未定义的行为是未定义的。
  • 大多数软件都包含许多缺陷和未定义的行为,这些缺陷和未定义的行为并不表现为实际的外部可观察问题。

标签: c++ visual-c++ clang


【解决方案1】:

这是未定义行为的本质——它可能完全按照您的意图进行。问题是,对于编译器、操作系统、库或 CPU 的下一版本……它可能会做一些完全不同的事情。

很可能,您会因为两个原因侥幸逃脱:

  1. int 没有析构函数。所以未能正确销毁数组中的每个元素没有任何后果。

  2. 在这个平台上,newnew[] 使用相同的分配器。因此,您不会将块返回给错误的分​​配器。

【讨论】:

  • 这是正确的。查看gcc's libstdc++clang's libc++ 中全局new/delete 的来源后,delete [] 在这些实现中似乎只是调用了delete
【解决方案2】:

让我们一步一步来看看会发生什么(但我们会忽略异常):

int *foo = new int[100];

这会分配100*sizeof(int) 字节的内存并调用int::int() 100 次,对数组中的每个元素调用一次。

由于int 是一个内置类型,它有一个简单的构造函数(即它什么都不做)。

现在,怎么样:

delete foo;

这会在foo指向的地址上调用int::~int(),然后删除foo指向的内存。同样,由于int 是一个内置类型,它有一个简单的析构函数。

比较一下:

delete [] foo;

它将为foo指向的数组中的每个项目调用int::~int(),然后删除foo指向的内存。

这里的基本区别是元素 1..99 不会被破坏。对于int,这不是问题,这可能就是您现有代码有效的原因。对于具有真正析构函数的对象数组,您会看到更多的不当行为。

附:如果你写了delete foo;,大多数实现都会删除foo指向的整个内存块,即使你用array-new分配了它——但你指望它是愚蠢的。

【讨论】:

  • 我之前没有看到这个答案。这是迄今为止最清楚的解释。
【解决方案3】:

这不起作用。删除没有[] 的数组会泄漏内存。如果您的应用程序长时间运行,它会影响性能。对于短期项目,不会有任何问题。

另外需要注意的是delete 将销毁所有由new 分配的内存。如果你已经通过new(不是new [])分配了一个数组,你可以使用delete 来销毁它`。

【讨论】:

  • @bikeshedder 见第二段。
【解决方案4】:

这不会导致程序崩溃,但每次这样做都会泄漏999 * sizeof(int) 字节的内存。

【讨论】:

  • 为什么不是1000 * sizeof(int)
  • 我认为这是因为您破坏了数组中的第一个元素。但不是其余的。
  • 我不认为你可以,一般地,提出这个要求。许多实现将释放连续的内存块,如调用free。否则,我认为崩溃比泄漏更有可能。
【解决方案5】:

常规的delete 运算符实际上可能会从数组中释放所有内存,具体取决于分配器,但真正的问题是它永远不会对数组元素运行任何析构函数。

【讨论】:

    猜你喜欢
    • 2015-10-19
    • 2015-11-22
    • 1970-01-01
    • 2011-01-02
    • 2016-05-25
    • 1970-01-01
    • 2017-06-08
    • 1970-01-01
    相关资源
    最近更新 更多