tjw*_*992 127 c++ pointers memory-management delete-operator visual-studio-2012
我一直在阅读的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;
}
Run Code Online (Sandbox Code Playgroud)
当我编译并运行该程序时,我得到以下输出:
ptr = 0050BC10
ptr = 00008123
Press any key to continue....
Run Code Online (Sandbox Code Playgroud)
显然,当调用delete时,指针指向的地址会发生变化!
为什么会这样?这是否与Visual Studio有关?
如果删除可以改变它指向的地址,为什么不删除自动设置指针NULL而不是一些随机地址?
tjw*_*992 173
我注意到存储的地址ptr总是被覆盖00008123...
这看起来很奇怪,所以我做了一点挖掘,发现这篇Microsoft博客文章包含了一节讨论"删除C++对象时自动指针清理".
...检查NULL是一种常见的代码构造,这意味着现有的NULL检查与使用NULL作为清理值相结合,可能偶然地隐藏了一个真正的内存安全问题,其根本原因确实需要解决.
出于这个原因,我们选择了0x8123作为清理值 - 从操作系统的角度来看,这与零地址(NULL)在同一个内存页面中,但是在0x8123处的访问冲突将更好地脱颖而出,因为需要更详细的关注.
它不仅解释了Visual Studio在删除后对指针的作用,还解释了为什么他们选择不NULL自动设置它!
此"功能"作为"SDL检查"设置的一部分启用.要启用/禁用它,请转到:PROJECT - > Properties - > Configuration Properties - > C/C++ - > General - > SDL check
要确认这一点:
更改此设置并重新运行相同的代码会产生以下输出:
ptr = 007CBC10
ptr = 007CBC10
Run Code Online (Sandbox Code Playgroud)
"功能"是因为在你有两个指针指向同一位置的情况下报价,呼吁删除只会消毒ONE他们.另一个将指向无效位置.
Visual Studio可以通过在设计中记录这个缺陷来为您设置一个棘手的情况.
Han*_*ant 30
您会看到/sdl编译选项的副作用.默认情况下,对于VS2015项目,它启用了除/ gs提供的安全检查之外的其他安全检查.使用项目>属性> C/C++>常规> SDL检查设置来更改它.
引用MSDN文章:
- 执行有限的指针清理.在不涉及解除引用的表达式中以及没有用户定义的析构函数的类型中,在调用delete之后,指针引用被设置为无效地址.这有助于防止重用过时的指针引用.
请记住,在使用MSVC时,将删除的指针设置为NULL是一种不好的做法.它会破坏您从Debug Heap和this/sdl选项获得的帮助,您无法再在程序中检测到无效的免费/删除调用.
R S*_*ahu 19
它还指出指针将继续指向同一位置,直到它被重新分配或设置为NULL.
这绝对是误导性的信息.
显然,当调用delete时,指针指向的地址会发生变化!
为什么会这样?这是否与Visual Studio有关?
这显然属于语言规范.ptr呼叫后无效delete.ptr在它之后使用delete是造成未定义行为的原因.不要这样做.运行时环境可以ptr在调用后随意执行任何操作delete.
如果删除可以改变它指向的地址,为什么不删除自动将指针设置为NULL而不是一些随机地址???
将指针的值更改为任何旧值都在语言规范内.至于把它改成NULL,我会说,那会很糟糕.如果指针的值设置为NULL,程序将以更合理的方式运行.但是,这将隐藏问题.当程序使用不同的优化设置进行编译或移植到不同的环境时,问题可能会出现在最不合时宜的时刻.
gio*_*gim 10
delete ptr;
cout << "ptr = " << ptr << endl;
Run Code Online (Sandbox Code Playgroud)
一般情况下,即使读取(如上所述,请注意:这与解除引用不同)无效指针的值(指针变为无效,例如当你使用delete它时)是实现定义的行为.这是在CWG#1438中引入的.另见这里.
请注意,在读取无效指针的值之前是未定义的行为,所以上面的内容将是未定义的行为,这意味着任何事情都可能发生.
| 归档时间: |
|
| 查看次数: |
7979 次 |
| 最近记录: |