在C ++中删除指针:`delete p`是什么意思?

时间:2013-06-10 10:45:00

标签: c++ pointers delete-operator

#include <iostream>
#include <cstdio>
using namespace std;

int main(void)
{
    int arr[] = {1,4,2,3,5,6};
    int *p = arr;
    delete p;

    for(int i = 0 ; i < 6; i++)
        cout << p[i];

    return 0;
}

输出为142356。 当我说delete p为什么不删除p?

运行代码时不应该出现分段错误吗?

4 个答案:

答案 0 :(得分:4)

正如一位聪明的中国老僧人曾经说过的那样,“未定义的行为是未定义的”。

说真的,尝试delete不是new d的东西是未定义的。

c和c ++都将其大部分意外功能定义为“未定义”。这意味着当你有这种行为时,你不知道会发生什么。如果你真的很幸运,它会出现故障或类似情况。更常见的是,会发生奇怪且无法解释的事情,试图推理它们在很大程度上是毫无意义的。

这样做的主要原因是编译器的实现既简单又更优。

作为一名C ++程序员,我建议你阅读Undefined Behavior,Unspecified Behavior和Implementation Defined Behavoir。它们对于理解任何适度有趣的c ++代码将如何运作都是至关重要的。

LLVM项目的blog关于未定义的行为是一个很好的阅读

答案 1 :(得分:2)

您有未定义的行为。

 int arr[] = {1,4,2,3,5,6};
 int *p = arr;
 delete p;

此处,arr创建时未动态分配。甚至你的指针p也没有动态分配。您无法在其上使用delete。当您使用delete [或delete[]]分配它,然后使用new释放动态分配的内存时,将使用new[] [或delete]。

定义指针(或声明)不会导致分配内存。您使用new

int * p = new int;  //later deleted as delete p;

int * p = new int[5]; //later deleted as delete[] p;

分配内存,然后删除它。 (此外,newdelete的数量必须相等并且在您的代码中对应)

答案 2 :(得分:1)

你正在使用“未定义的行为”,在这种情况下使用免费后的指针(并释放一些不是来自新的东西) - C ++(如C)设计得很快。因此,它不会执行“不必要的”操作,例如在删除对象时检查内存是什么或用其他内容填充内存。它只是将内存标记为“空闲”,并且当您稍后分配其他内容时,它将(或可能选择)将该内存用于新分配。

如果你有一个类而不是一个简单的int,你可以让析构函数写入类的成员变量并清除它。但对于内置类型,例如intlongdouble等,则无法完成任何操作。

请注意,不明确的行为只是 - 未定义。它可以并且将会做除你期望之外的其他事情 - 但它也可以完美地完成你的期望。部分原因取决于您的期望。关键是标准没有说明当你做某事时将会发生什么(例如,标准没有声明“使用已经使用删除释放的内存必须导致崩溃”或“必须将通过删除释放的内存设置为值X“ - 它也没有说使用释放的内存不会导致崩溃,或者内存无法更改为某个新值。

同样地,如果您释放未分配新内容的内容,标准也没有说明您应该期待什么。相反,它说它是“未定义的行为”。最有可能的是,如果您现在尝试使用new,它可能会失败,因为您的堆已经搞砸了。

答案 3 :(得分:0)

delete运算符用于通知管理内存的任何人,程序不再需要已分配的内存,哪个地址存储在已删除的指针中,并且可以被释放。

请记住,C ++不仅针对Win32或Linux进行了编译。可能有更多的平台,以不同的方式管理他们的记忆。这就是为什么标准没有明确定义,释放内存会发生什么。在您的特定情况下,内存被标记为空闲(如果您分配并填充了该大小的另一个数组,之前的,已释放的一个可能已被覆盖,但不一定),但其内容未被破坏。

内存管理的这种实现有助于提高性能:用零(或其他值)覆盖释放内存的重点是什么,如果很快就会再次使用并填充其他数据?

现在为什么你试图从那个内存中读取没有引起AV?可能,因为整个内存块(该阵列所在的位置)是为您的进程保留的,所以它仍然试图从自己的内存中读取。我猜测,尝试写入该内存可能导致AV(但可能没有,它也是特定于实现的。)

一般规则就是不使用由删除释放的内存,因为 - 正如标准所说 - 你不能保证它的可访问性,也不保证它被释放后的内容。