Visual Studio如何处理删除的指针,为什么?

我一直在阅读的一本C ++书籍指出,当使用delete操作符删除一个指针时,它所指向的位置上的内存被“释放”,并且可以被覆盖。 它还指出指针将继续指向相同的位置,直到它被重新分配或设置为NULL

但是在Visual Studio 2012中, 这似乎并不是这样!

例:

 #include <iostream> using namespace std; int main() { int* ptr = new int; cout << "ptr = " << ptr << endl; delete ptr; cout << "ptr = " << ptr << endl; system("pause"); return 0; } 

当我编译和运行这个程序,我得到以下输出:

 ptr = 0050BC10 ptr = 00008123 Press any key to continue.... 

显然,指针所指向的地址在调用删除时会发生变化!

为什么发生这种情况? 这与Visual Studio具体有什么关系吗?

如果删除可以改变它指向的地址,为什么不删除自动将指针设置为NULL而不是一些随机地址?

我注意到,存储在ptr中的地址总是被00008123覆盖…

这似乎很奇怪,所以我做了一点挖掘,发现这个微博客post里有一个讨论“删除C ++对象时自动指针清理”的部分。

…检查NULL是一种常见的代码构造,意味着现有的NULL检查与使用NULL作为清理值相结合可能偶然地隐藏真正的内存安全问题,其根本原因确实需要寻址。

因为这个原因,我们select0x8123作为一个消毒值 – 从操作系统的angular度来看,它和零地址(NULL)在同一个内存页面,但是0x8123的访问冲突会更好的体现出来, 。

它不仅解释了Visual Studio在删除指针后所做的工作,还解释了为什么他们select不自动将其设置为NULL


此“function”作为“SDL检查”设置的一部分启用。 要启用/禁用它,请转到: PROJECT – >属性 – >configuration属性 – > C / C ++ – >常规 – > SDL检查

为了证实这一点:

更改此设置并重新运行相同的代码将生成以下输出:

 ptr = 007CBC10 ptr = 007CBC10 

“function”是用引号括起来的,因为在有两个指向同一位置的指针的情况下,调用delete只会消除其中的一个。 另一个将被指向无效的位置。

Visual Studio可以通过在devise中没有logging这个缺陷来设置你的粘性。

您将看到/sdl编译选项的副作用。 默认情况下启用VS2015项目,它启用超出/ gs提供的安全检查。 使用项目>属性> C / C ++>常规> SDL检查设置来改变它。

从MSDN文章引用:

  • 执行有限的指针消毒。 在不涉及解除引用的expression式中,在没有用户定义的析构函数的types中,在删除调用之后,指针引用被设置为非有效地址。 这有助于防止重新使用陈旧的指针引用。

请记住,当您使用MSVC时,将删除的指针设置为NULL是不好的做法。 它无法从Debug Heap和this / sdl选项中获得帮助,您将无法再在程序中检测到无效的自由/删除调用。

它还指出指针将继续指向相同的位置,直到它被重新分配或设置为NULL。

这绝对是误导性的信息。

显然,指针所指向的地址在调用删除时会发生变化!

为什么发生这种情况? 这与Visual Studio具体有什么关系吗?

这显然在语言规范之内。 delete电话后, ptr无效。 在delete d之后使用ptr会导致未定义的行为。 不要这样做。delete呼叫之后,运行时环境可以随意地使用ptr来执行任何操作。

如果删除可以改变它指向的地址,为什么不会自动将指针设置为NULL而不是一些随机地址?

将指针的值更改为任何旧值都在语言规范内。 至于将其更改为NULL,我会说,这将是不好的。 如果指针的值被设置为NULL,那么程序的行为将会更加健全。 但是,这将隐藏问题。 当程序编译时使用不同的优化设置或移植到不同的环境时,问题可能会出现在最不合适的时刻。

 delete ptr; cout << "ptr = " << ptr << endl; 

一般情况下,甚至是读取 (像上面这样做,请注意:这与取消引用不同)无效指针的值(例如,当您delete它时指针变为无效)是实现定义的行为。 这是在CWG#1438中介绍的。 另见这里 。

请注意,在无效指针的读取值是未定义的行为之前,所以你上面的将是未定义的行为,这意味着可能发生任何事情。

我相信,你正在运行某种debugging模式,而VS正试图将你的指针重新指向某个已知的位置,所以进一步尝试去引用它可以被追踪和报告。 尝试在发行模式下编译/运行相同的程序。

为了提高效率,指针通常不会在内部delete而被改变,并且避免给出错误的安全想法。 将删除指针设置为预定义值在大多数复杂场景中都不会有效,因为删除的指针可能只是指向此位置的指针之一。

事实上,我越想越想象VS一如既往的错误。 如果指针是const,该怎么办? 它还会改变吗?

删除指针后,指向的内存可能仍然有效。 为了显示这个错误,指针值被设置为一个明显的值。 这真的有助于debugging过程。 如果该值设置为NULL ,则可能永远不会在程序stream中显示为潜在错误。 所以当你在后面testingNULL时候它可能会隐藏一个bug。

还有一点是,某些运行时优化器可能会检查该值并更改其结果。

在早些时候,MS将该值设置为0xcfffffff