运算符“delete []”:如何检测?如果误用“删除”,行为?

时间:2016-05-06 00:16:01

标签: c++ visual-studio-2008

我使用的是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?
  2. 如果我在项目中使用“Code1”,

    1. 它会破坏堆(什么样的腐败)?
    2. 未定义的行为或定义的行为?

2 个答案:

答案 0 :(得分:2)

首先:不要这样做。只是不要。基本上永远是使用new的数组形式的一个很好的理由(对于反对者:不,甚至在你写一个集合类时)。我在实际代码中已经使用了20多年(之前不应该使用,但当时没有意识到)。通常,您应该使用std::vector代替。

然后简短的回答:我不知道将会诊断出这个(至少是可靠的)编译器。当/如果你这样做,就会得到未定义的行为,这基本上意味着你已经破坏了与编译器签订合同的一面,从而消除了它的所有义务。

至于在实践中可能发生的事情:这似乎随编译器而变化。在某些情况下,你的内存块将被释放而不运行它包含的对象的析构函数(在你的情况下无关紧要,因为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次。

答案 1 :(得分:1)

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

  

它会破坏堆(什么样的腐败)?

未定义,因为未正确删除数组的行为。它可能工作得很好。它可能会破坏记忆。它可能会破坏堆。它可能会使你的程序崩溃。

这就是“未定义的行为”的含义。