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....

显然,当调用delete时,指针指向的地址会发生变化!

这是为什么发生? 这是否与Visual Studio具体有关?

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


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

这看起来很奇怪,所以我做了一点挖掘,发现这篇Microsoft博客文章包含一节讨论“删除C ++对象时自动指针清理”。

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

由于这个原因,我们选择0x8123作为清理值 - 从操作系统的角度来看,它与零地址(NULL)位于同一内存页面,但0x8123访问冲突更适合开发人员,因为需要更加详细的关注。

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


此“功能”作为“SDL检查”设置的一部分启用。 要启用/禁用它,请转到: PROJECT - > Properties - > Configuration Properties - > C / C ++ - > General - > SDL checks

为了证实这一点:

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

ptr = 007CBC10
ptr = 007CBC10

“功能”在引号中,因为在有两个指向同一位置的指针的情况下,调用delete只会清理其中的一个。 另一个将被指向无效位置。

Visual Studio可能会因为未能在其设计中记录这个缺陷而给你提供一个棘手的情况。


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

从MSDN文章引用:

  • 执行有限的指针清理。 在不涉及解除引用的表达式以及没有用户定义的析构函数的类型中,在删除调用之后,指针引用被设置为非有效地址。 这有助于防止重新使用陈旧的指针引用。
  • 请记住,当您使用MSVC时,将删除的指针设置为NULL是不好的做法。 它击败了您从Debug Heap和this / sdl选项中获得的帮助,您不能再在程序中检测到无效的免费/删除调用。


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

    这绝对是误导性的信息。

    显然,当调用delete时,指针指向的地址会发生变化!

    这是为什么发生? 这是否与Visual Studio具体有关?

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

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

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

    链接地址: http://www.djcxy.com/p/31665.html

    上一篇: What does Visual Studio do with a deleted pointer and why?

    下一篇: Does Java Allow Direct Memory Access