C ++:动态分配的变量未在Clang

时间:2018-04-24 18:10:30

标签: c++ pointers clang

沃尔特·萨维奇的“用C ++解决问题,第9版''第517页的州:

  

将delete应用于指针变量时,它所指向的动态变量将被销毁。此时,指针变量的值未定义,这意味着您不知道它指向的位置,也不知道它指向的值。此外,如果某个其他指针变量指向被销毁的动态变量,那么另一个指针变量也是未定义的。

但是,似乎在clang-902.0.39.1下,删除指针并不妨碍我使用该变量的能力。以下是演示此行为的简短示例:

int *p1, *p2;
p1 = new int(3);
p2 = p1;

cout << *p1 << endl << *p2 << endl;

delete p1;

cout << *p1 << endl << *p2 << endl;

使用此代码,我在单独的行上输出了4 3个。我希望在p1之后引用p2delete p1;时会出现错误,我不应该这样做吗?

在Visual Studio的C ++编译器中,引用p2输出一个较大的负数,表示我们引用的内存不属于我们,访问p1会导致程序崩溃。

4 个答案:

答案 0 :(得分:4)

  

我希望在删除p1之后引用p1和p2时会发生错误,我不应该这样做吗?

不一定。

  

此时,指针变量的值未定义

未定义,如在调用delete之后使用指针可能会导致任何事情发生,好,坏或中立。

编译器不需要为进一步使用指针设置任何运行时障碍。特别是,不需要立即结束程序。当然,一个好的编译器(使用正确的设置)可能会警告你,如果它看到你的代码重用了删除的指针。

  

在Visual Studio的C ++编译器中,引用p2会输出一个较大的负数,表示我们正在引用不属于我们的内存,而访问p1会导致程序崩溃。

特定编译器可能会创建一个进程,该进程在特定操作系统下,在特定内存负载条件下会导致崩溃。或者它可能不会。类似地,不要求与指针相关联的存储器充满垃圾数据。

特别是,我相信调试版本中的Visual Studio可能会检测指针的内存,以便进一步使用会导致崩溃/异常。这对于可调试性非常有用。

除了调试版本之外,唯一可能导致的问题是偶然的。对于已调用delete然后重用的指针,请考虑以下可能性:

  • 该进程已将内存释放到操作系统。您的程序现在正在尝试访问它无权访问的内存。 SEGFAULT(崩溃)。
  • 在内部,内存已被标记为属于另一个变量(即程序的其他部分称为new或类似),并已写入。它似乎充满了垃圾数据。根据程序如何使用变量,可能存在问题,也可能不存在问题。它可能会崩溃,可能会打印出乱码等文本。
  • 在内部,内存被标记为已删除,但程序的其他任何部分都不需要它。目前,记忆保持不变。这就是你在clang下看到的,大概是。

简而言之,虽然预测删除指针的内存会发生什么变化是棘手的,但给程序员的唯一责任是:不再使用它。

答案 1 :(得分:1)

当您删除指针并且指针仍然指向它时,该内存仍然存在。但是,您无法保证它仍然有效或将来仍然存在。内存分配(new / malloc / etc)已将内存中的位置标记为不再使用,因此它可能会重新分配它或释放页面上的所有内存,此时访问它将导致访问冲突(段错误)。

例如,如果我使用指针创建三个新的int,它们可能会在内存中彼此相邻放置。如果我删除中间指针,它的地址仍然有效,因为在它的所有内存不再有效之前,无法释放内存页面。但是,即使我可以访问现在删除指针的内存,我也不应该这样做。那是因为如果我创建一个新的int指针,它可能会被分配到那个新的位置。

BAD METAPHOR:记忆就像教室里的座位一样。有些人需要更多的座位(或站起来或放置他们的行李),有些人需要更少。在教室中的所有座位都免费之前,您无法从学校中移除教室。如果您要求获得一个座位,您可以获得room1,seat2。如果你放弃那个座位(比如删除一个指针),你仍然可以参考room1 / seat2,即使它不再是你的。如果您试图坐在其中,您可能会发现其他人已被分配。如果你坐在里面,教室可能会随时关闭,因为你说你已经完成了座位。

seat =指针指向的内存

教室=记忆页

答案 2 :(得分:0)

你的指针仍然指向旧位置,只是这个记忆不再属于他们了。稍后可能会有另一个数据。所以这不是稳定的输出。

答案 3 :(得分:0)

内存已经释放,但你的指针仍然指向数据所在的位置。