首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包
c++析构函数的疑问
发表时间:2007-07-02 12:01:55   楼主:nemo0976

#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;

};





 
发表时间:2007-07-03 07:30:41 1 楼:miraclezone520

但是它(指针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 所指向的地址是没有改变啊!!!!

 

 

发表时间:2007-07-03 09:03:28 2 楼:stoundmire
是不是此时f已经变成了悬空指针,再进行操作是很危险的?
发表时间:2007-07-03 11:06:47 3 楼:nemo0976
因为释放的内存空间应为堆栈地址,而C++中的new\delete操作符号是封装了OS的API函数,就用windows平台来说,系统将跟踪该每个生成进程虚拟地址的动态情况,当申请一块堆栈内存空间,系统将把该地址块空间标名保留或提交.而我们在一般在程序中操作的地址也只是逻辑地址,而当虚拟地址没有正式提交给物理内存,是不能被操作的.而delete应该也是把该逻辑地址的标为不可用(如果需要再次使用应该使用new进行重新申请),所以当一个指针继续访问一个被标为不可用的地址时,应该产生一个异常错误.但是为什么上面的程序依然可以正常运行呢?
发表时间:2007-07-04 09:19:50 4 楼:plainsong

因为释放的内存空间应为堆栈地址,而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-04 13:44:56 5 楼:dai_weitao
这个指针的空间已经释放了, 应该是编译器的bug, 楼主用的是VC6吧.
发表时间:2007-07-05 16:52:15 6 楼:nemo0976
gcc 3.4.2  for windows
本回复于:
2007-07-05 16:54:20 被【nemo0976】修改
发表时间:2007-07-05 18:07:22 7 楼:wangshh
f 存的是b->m_ptr所指向的内存空间(堆上)的首地址,当delete b;后b->m_ptr所指向的内存空间已经被释放(其实b->m_ptr已经不存在了),但是因为局部变量f本身并没有被释放,它所存储的值当然也不会变化,这时候f指向一个并不存在的内存空间变成一个野指针,这时再对f解引用(*f)就会产生异常。
发表时间:2007-07-07 16:00:14 8 楼:hoof_2007

看不懂,但是我最近半年一定会常来这里看的

 

发表时间:2007-07-13 09:55:40 9 楼:danranyixiao
~a(){delete m_ptr;m_ptr=0;}   你这里应该换成~a(){delete[] m_ptr;m_ptr=0;} 因为这是数组~!~呵呵~!~
发表时间:2007-07-29 10:15:43 10 楼:skyyby

 --------------------------------------------------------------------

但是它(指针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; 不一样

他们有什么区别呢??哪位前辈能谈谈呀

小弟先谢谢了

发表时间:2008-03-30 18:35:10 11 楼:xsy19880914

 空间被释放,

但是它还是存在的

就像把房子里的东西移走

但房子还是存在的一样啊

发表时间:2008-07-05 16:28:36 12 楼:zhous001
在VC6里面经过一步步调试发现F的值确实改变了的,最开始的char *f=new a();时候f的值跟delete b 后f的值不一样,但是为什么你输出的一样我就搞不懂了的。
发表时间:2008-08-20 12:10:18 13 楼:hellenck

一个进程有自己的数据块,堆、栈和代码区。同一个进程内的空间你是可以访问的(即使你没有申请空间)。

所以你上面所谈到就是一个很正常的现象:你即使把申请的空间释放了,但你还是可以访问这个空间的,只要你知道这个空间的地址。

这也就是我要谨慎防止出现悬浮指针的道理,因为可能会出现这种情况:你释放的m_ptr所指向的空间有可能被别处申请到了,而你接下来的f又修改了这个空间从而破坏了最后一次申请所需要的数据。

发表时间:2008-08-26 09:35:06 14 楼:zhujt1981

楼主程序太烂了

网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|版权声明|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo