-3
#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

4 回答 4

5

正如一位睿智的中国老僧所说,“未定义的行为是未定义的”。

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

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

这样做的主要原因是编译器的实现可以更简单也更优化。

作为一名 C++ 程序员,我建议您阅读未定义的行为、未指定的行为和实现定义的行为。它们都是理解任何适度有趣的 c++ 代码将如何运行的基础。

LLVM 项目关于未定义行为的博客是一本很好的读物

于 2013-06-10T11:06:00.510 回答
3

你有未定义的行为。

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

在这里,arr创建不是动态分配的。甚至您的指针p也不是动态分配的。你不能delete在上面使用。当您使用[or delete]分配它然后使用释放动态分配的内存时,使用 [or ]。delete[]newnew[]delete

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

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

或者

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

等等

分配内存,然后将其删除。(另外,代码中new和的数量delete必须相等且对应)

于 2013-06-10T11:21:17.847 回答
1

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

如果你有一个类而不是一个简单的int,你可以让析构函数写入类的成员变量并清除它。int但是对于诸如, long,等的内置类型double,什么都做不了。

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

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

于 2013-06-10T11:11:18.017 回答
0

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

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

这种内存管理的实现服务于性能的目的:用零(或其他值)覆盖释放的内存有什么意义,如果它很快会再次使用并填充另一个数据?

现在为什么您尝试从该内存中读取并没有导致 AV?可能是因为该数组所在的整个内存块是为您的进程保留的,所以它仍在尝试从自己的内存中读取。我,尝试写入该内存可能会导致 AV(但可能没有,它也是特定于实现的)。

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

于 2013-06-10T11:06:10.023 回答