#include <iostream>
using namespace std;
class a{
public:
char *m_ptr;
public:
a(){m_ptr=new char[1];*(m_ptr+9)='/0';}
~a(){delete m_ptr;m_ptr=0;}
};
int main(){
a *b=new a();
char *f=b->m_ptr;
delete b;
*f='a'; //指针'f'指向的内存堆栈地址应该已经被类a的析构函数所释放,但为什么指针'f'依然能操作该地址空间呢?
system("pause");
return 0;
};
但是它(指针f)依然是指向一片内存的阿!!
只不过这块内存被清空,
被操作系统标记为没有被使用而已 .......
我测试过了!!我输出了delete前后f所指向的地址,发现是一样的啊!!你试试看!!
//class ............
int main()
{
a *b=new a();
char *f=b->m_ptr;
cout<<static_cast<void*>(b->m_ptr)<<endl; 输出 b->m_ptr 所指向的地址
cout<<static_cast<void*>(f)<<endl; 输出delete b前, f 所指向的地址
delete b;
cout<<static_cast<void*>(f)<<endl; 输出delete b后, f 所指向的地址
system("pause");
return 0;
}
你会发现 f 所指向的地址是没有改变啊!!!!
因为释放的内存空间应为堆栈地址,而C++中的new\delete操作符号是封装了OS的API函数,就用windows平台来说,系统将跟踪该每个生成进程虚拟地址的动态情况,当申请一块堆栈内存空间,系统将把该地址块空间标名保留或提交.而我们在一般在程序中操作的地址也只是逻辑地址,而当虚拟地址没有正式提交给物理内存,是不能被操作的.而delete应该也是把该逻辑地址的标为不可用(如果需要再次使用应该使用new进行重新申请),所以当一个指针继续访问一个被标为不可用的地址时,应该产生一个异常错误.但是为什么上面的程序依然可以正常运行呢?
这与具体实现有关,没有规定要求这时必须“产生一个异常错误”,因为这会影响内存管理代码的工作效率;而访问释放的内存块属于错误代码,本就不就在程序中出现,为错误代码而付出代价是不值得的。
new和delete的内存分配部分通常并不只是封装了OS的API函数。我记得在VC6中是直接调用HeapAlloc和HeapFree在事先用HeapCreate创建的堆中分配的,这两个函数比LocalAlloc/GlobalAlloc要快一些,但是否会在访问已释放的内存块时“产生一个异常错误”,我没有试过,有兴趣的人可以自已试验一下。而BCB6提供的代码就复杂多了。事实上,VC6的内存分配/释放的效率实在是让人不满意。记得以前在讨论loki库的时候,有人说它的“小对象分配器”在时间效率上没什么提高,而有人说有很大提高,其实说“没什么提高”的用的是BC,而说“有很大提高”的用的就是VC。
一般情况下,编译器会提供调试版和发行版两个不同的库,在调试版本的库中,会在释放内存时用一个固定数字填充分配的内存块(比如0xcdcdcdcd)。这样当你用调试版本编译的话,如果访问释放后的内容,就会发现它的值发生了变化。如果这个值是指针类型,你对它作“消引用”操作时,就很可能会“产生一个异常错误”,因为这时这个值所代表的内存地址很可能不在你的进程控制之下。这是为了帮助程序员更容易地发现错误。而在发行版本中,这些处理都将去除。
2007-07-05 16:54:20 被【nemo0976】修改
看不懂,但是我最近半年一定会常来这里看的
--------------------------------------------------------------------
但是它(指针f)依然是指向一片内存的阿!!
只不过这块内存被清空,
被操作系统标记为没有被使用而已 .......
我测试过了!!我输出了delete前后f所指向的地址,发现是一样的啊!!你试试看!!
//class ............
int main()
{
a *b=new a();
char *f=b->m_ptr;
cout<<static_cast<void*>(b->m_ptr)<<endl; 输出 b->m_ptr 所指向的地址
cout<<static_cast<void*>(f)<<endl; 输出delete b前, f 所指向的地址
delete b;
cout<<static_cast<void*>(f)<<endl; 输出delete b后, f 所指向的地址
system("pause");
return 0;
}
你会发现 f 所指向的地址是没有改变啊!!!!
-------------------------------------------------
我在system("pause");这句前加了cout<<f<<endl;显示结果与cout<<static_cast<void*>(f)<<endl; 不一样
他们有什么区别呢??哪位前辈能谈谈呀
小弟先谢谢了
空间被释放,
但是它还是存在的
就像把房子里的东西移走
但房子还是存在的一样啊
一个进程有自己的数据块,堆、栈和代码区。同一个进程内的空间你是可以访问的(即使你没有申请空间)。
所以你上面所谈到就是一个很正常的现象:你即使把申请的空间释放了,但你还是可以访问这个空间的,只要你知道这个空间的地址。
这也就是我要谨慎防止出现悬浮指针的道理,因为可能会出现这种情况:你释放的m_ptr所指向的空间有可能被别处申请到了,而你接下来的f又修改了这个空间从而破坏了最后一次申请所需要的数据。
楼主程序太烂了
