是否期望删除[]的这种行为 - 只删除前两个元素?

时间:2014-04-25 20:22:25

标签: c++ memory-management new-operator

我的代码:

#include<iostream>
#include<cstdlib>

using namespace std;

int main()
{
    int * p;
    p = new int[5];
    p[0] = 34;
    p[1] = 35;
    p[2] = 36;
    p[3] = 44;
    p[4] = 32;
    cout << "Before deletion: " << endl;
    for (int i = 0; i < 5; i++)
    {
        cout << p[i] << endl;
    }

    delete[] p;
    cout << "After deletion: " << endl;
    for (int i = 0; i < 5; i++)
    {
        cout << p[i] << endl;
    }
}

如果delete[]应该删除new创建的所有内存块,那么为什么只有前两个元素被删除?

这是输出:

Before deletion: 
34
35
36
44
32
After deletion: 
0
0
36
44
32

我能想到的一个可能的原因是它删除了前两个,其中一些内存管理认为整个块可以在需要时再次重新分配。虽然这是我的完全猜测,但我不知道真正的原因。

5 个答案:

答案 0 :(得分:3)

没有必要清除(如更改值)delete d元素,它只意味着分配器可以自由地使用它所占用的空间来满足任何需要的空间,并且访问值会导致未定义的行为。

你遇到了一个非常令人讨厌的结果,即某些值保持不变,而同一程序的连续运行可能(并且你应该假设那样)会有不同的结果。

答案 1 :(得分:2)

不是前两个项目已删除,而是全部删除。现在可以通过进一步的新操作重用该存储区,但不能保证该存储区中剩余的内容。

完全有可能您会看到不同机器,后续在同一台机器上运行,不同编译器版本等的不同结果。只是不要依赖它。

但是,您之后正在访问一个悬空指针,即未定义的行为(简称UB)。

以防万一,如果在没有方括号的情况下调用delete,则所有内存都将被解除分配,但可能无法调用析构函数。即使在这种情况下你没有自定义类型,也就是整数,这也是UB。

在您的情况下,它与deletedelete[]的UB行为完全相同。这就是为什么你在当前的运行中都看到相同结果的原因,但是再次,即使这样也不能保证。

理想情况下,您还需要将它们设置为零,但实际上,您应该考虑使用智能指针,例如unique_ptr

答案 2 :(得分:1)

问:如果删除[]应该删除新创建的所有内存块,那么为什么只有前两个元素被删除?

答:结论不正确。请尝试以下方法:

#include <iostream>

struct A
{
   A() : a(0) {}
   ~A() { std::cout << "Came to ~A(). a = " << a << std::endl;}
   int a;
};

int main()
{
   A* ap = new A[5];
   for (int i = 0; i < 5; ++i )
   {
      ap[i].a = i;
   }

   delete [] ap;
}

我得到以下输出:

Came to ~A(). a = 4
Came to ~A(). a = 3
Came to ~A(). a = 2
Came to ~A(). a = 1
Came to ~A(). a = 0

答案 3 :(得分:1)

指针不是魔法。它实际上是机器字大小的无符号整数,它指的是存储器地址。将内存位置的值从任何值更改为0都不会删除任何内容。当您致电deletedelete []时,您所做的一切都被告知内存分配器您已经完成了该内存,并且可以随心所欲地执行(或不执行)任何操作。在调用delete之后,该内存中的内容未定义,您无权期望它包含任何内容,并且您无权访问它。访问已被释放的内存就像进入一个你移出的公寓,你还有一把钥匙;你可能会逃脱它,或者你可能会违反访问权限。

对于带有析构函数的类型,内存分配器将在回收内存块之前为内存块中的每个对象调用析构函数。 int没有析构函数,所以没有什么可以做的。

答案 4 :(得分:0)

delete[] p释放p所占用的内存,但不会(必然)覆盖它。旧数据将无限期地保留在那里。