operator "delete[]": 如何检测?误用 "delete" 时的行为?

operator "delete[]": how to detect? Behavior if misuse with "delete"?

我使用的是 Visual Studio 2008 并编译了以下代码。

代码 1:

int* pI = new int[3];
delete pI;

代码2:

int* pJ = new int[3];
delete[] pJ;

很明显,Code1是错误的,因为pI是用"operator new[]"分配的。

那么问题来了:

  1. 编译器无法选择这个错误(太糟糕了),这只是VS2008的行为吗? Visual Studio、g++、clang 的更高版本如何?

如果我在项目中使用"Code1",

  1. 它会破坏堆吗(哪种破坏)?
  2. 未定义的行为还是已定义的行为?

一些带有静态分析工具的编译器可以检测到 static 事件,例如您代码中的事件,这些事件永远无法正常运行。但他们无法在所有情况下检测到所有这些错误。特别动态的案例。

Will it corrupt the heap (what kind of corrupt)?

未定义,因为未定义错误删除数组的行为。它可能工作得很好。它可能会浪费内存。它可能会破坏堆。它可能会使您的程序崩溃。

这就是 "undefined behavior" 的意思。

首先:不要这样做。只是不要。本质上 永远不会 有充分的理由使用 new 的数组形式(对于反对者:不,即使在编写集合 class 时也不行)。我已经 20 多年没有在实际代码中使用过(在那之前不应该使用,但当时没有意识到)。通常,您应该使用 std::vector

然后是简短的回答:我不知道有哪个编译器可以对此进行诊断(至少是可靠的)。 When/if 你这样做了,你得到了未定义的行为,这基本上意味着你违反了你与编译器的合同,编译器取消了它的所有义务。

至于在实践中可能发生的情况:这似乎因编译器而异。在某些情况下,您的内存块将在没有 运行 包含它包含的对象的析构函数的情况下被释放(在您的情况下无关紧要,因为 int 的 dtor 基本上是一个 nop)。在其他情况下,代码会崩溃并烧毁。例如,考虑以下代码:

#include <iostream>
#include <iomanip>

struct foo {
    ~foo() { std::cout << "~foo()\n"; }
};

int main() {
    foo *g = new foo[5];   
    delete g;
}

对于 VS 2015 或 g++ 5.3,这会崩溃并烧毁(即弹出一个对话框,告诉您程序已停止工作)。

对于一些较旧的编译器,析构函数只会 运行 一次,而不是销毁所创建对象所需的 5 次。