以错误的方式删除数组

时间:2010-11-02 13:22:37

标签: c++ memory-management

  

可能重复:
  How could pairing new[] with delete possibly lead to memory leak only?

我总是被告知在使用new []分配的数组上调用delete是不安全的。你应该总是将new与delete和new []与delete []配对。

所以我很惊讶地发现以下代码在VS2008下的Debug和Release模式下编译并运行正常。

class CBlah
{
public:
    CBlah() : m_i(0) {}

private:
    int m_i;
};

int _tmain(int argc, _TCHAR* argv[])
{
    for(;;)
    {
        CBlah * p = new CBlah[1000]; // with []
        delete p;                    // no []
    }
    return 0;
}

我花了一段时间才弄明白为什么这种情况起作用,我认为这只是运气和一些未定义的行为。

但是......它让我想知道......为什么Visual Studio没有选择它,至少在Debug内存管理器中?是因为那里有很多代码会导致这个错误并且他们不想破坏它,或者他们觉得调度内存管理器的工作不是要抓住这种错误吗?

有什么想法?这种滥用是否常见?

9 个答案:

答案 0 :(得分:9)

它肯定会编译好,因为指针(编译时)中没有信息,它会看到指针指向数组还是什么。例如:

int* p;

cin>>x;
if(x == 0)
  p = new int;
else
  p = new int [10];

delete p; //correct or not? :)

现在,关于运行正常。这在C ++中称为未定义行为,也就是说,无法保证会发生什么 - 一切都可以正常运行,你可以得到一个段错误,你可以得到错误的行为,或者你的计算机可能决定拨打911.UB< = >不保证

答案 1 :(得分:3)

这是未定义的行为,在爱情,战争和未定义的行为中,一切都是公平的...... :)

答案 2 :(得分:1)

根据MDSN,它在尝试删除数组时将delete转换为delete []。 (例如,见there)。虽然编译后你应该收到警告。

答案 3 :(得分:1)

调试内存管理器没有发现此错误的原因可能是因为它没有在new / delete级别实现,而是在内存管理器级别上通过调用 new / delete分配所需的内存 那时,数组new和标量new之间的区别就消失了。

答案 4 :(得分:0)

您可以阅读这些有关deletedelete[]的答案和链接:About delete, operator delete, delete[], ...

答案 5 :(得分:0)

我不知道是什么让你觉得“工作正常”。它编译并完成而不会崩溃。这并不意味着必然没有泄漏或堆损坏。此外,如果你这次离开它,它并不一定能使它成为安全的事情。

有时即使是缓冲区覆盖也是你会“逃避”的东西,因为你写的字节没有被使用(也许它们是用于对齐的填充)。你还是不应该去做。

顺便说一句,新的T [1]是new []的一种形式,仍然需要删除[],即使在这种情况下只有一个元素。

答案 6 :(得分:0)

有趣的一点。 一旦我进行了代码审查并试图说服程序员修复新的[] - 删除不匹配。 我用Scott Meyers的Effective C ++论述了“第5项”。然而,他们争辩说“你想要什么,它运作良好!”并证明,没有内存泄漏。 但是,它仅适用于POD类型。看起来,MS试图解决Raveline指出的不匹配问题。

如果添加了析构函数会发生什么?

#include <iostream>
class CBlah
{
  static int instCnt;
public:
    CBlah() : m_i(0) {++instCnt;}
    ~CBlah()
    {
      std::cout <<"d-tor on "<< instCnt <<" instance."<<std::endl;
      --instCnt;
    }
private:
    int m_i;
};

int CBlah::instCnt=0;

int main()
{
    //for(;;)
    {
        CBlah * p = new CBlah[10]; // with []
        delete p;                    // no []
    }
    return 0;
}

无论VS中添加了什么愚蠢的“智能”修复,代码都不可移植。

答案 7 :(得分:0)

请记住,“正常工作”属于“未定义行为”的范畴。特定版本的特定编译器很可能以一种适用于所有意图和目的的方式实现它。要记住的重要一点是这不能保证并且您无法确定它是否正常工作,并且您无法知道它将适用于下一版本的编译器。它也不可移植,因为另一个编译器可能以不同的方式工作。

答案 8 :(得分:-1)

这是有效的,因为它链接的特定C ++运行时库对operator newoperator new[]使用相同的堆。许多人这样做,但有些人没有,这就是为什么不推荐这种做法的原因。

另一个很大的区别是,如果CBlah有一个非平凡的析构函数,delete p;只会为数组中的第一个对象调用它,而delete[] p;肯定会调用它它适用于所有物体。