智能车制作

 找回密码
 注册

扫一扫,访问微社区

查看: 1429|回复: 2
打印 上一主题 下一主题

堆释放(转)

[复制链接]

1

主题

11

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
274
威望
237
贡献
35
兑换币
0
注册时间
2010-5-1
在线时间
1 小时
跳转到指定楼层
1#
发表于 2010-5-1 10:33:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
堆、栈、静态全局区、常量区、代码区我就不介绍了,这些是先备知识。
大家可以去百度搜很多相关的文章。包括内存的申请方式,系统响应,编译区别,优缺点,以及各种内存占用的实质等等。
由于前段时间给公司写的程序构架有些乱,后来终于出了问题。事情源于这个程序,(当然简化了很多)。
int *p2=new int;
int *p1=new  int [2];
p1[0]=11;p1[1]=22;
p2=p1;
cout<<"*p1="<<*p1<<endl;
cout<<"p1[1]="<<p1[1]<<endl;
cout<<"*p2="<<*p2<<endl;
delete p2; ///////注意这句话
cout<<"*p1="<<*p1<<endl;
cout<<"p1[1]="<<p1[1]<<endl;
cout<<"*p2="<<*p2<<endl;


其结果是,P1 P2都释放了。但是这不是我的意图,为什么呢?IED都干了些什么?
先说一下C和C++里的释放这个含义。即free delete,它们是和malloc 和new成对使用的。
    释放是针对指针(即p)来说的.在指针对象的值(即*p)赋值之前必须有自己的一块内存区间,不然就是野指针。换句话说,指针要使用,必须指定一个内存,或一块内存。
OK,这样一来,它就死死地占有了这个内存或这块内存。就算你不用它了,它还是占着,不给其它需要的变量用。因此,必须释放掉。
    我理解的"释放":把内存的占有权给别人了,但是P这个指针还是那个数,只是指针指的值(*p)变成随机的,或者为0(根据编译器来定)。千万不要认为是把p和*p给灭掉了。new P了之后,P这块内存就是P的了,以后分配其它的堆的时排除这个内存,而delete之后,这个排除能力就消失了。我的理解可能还不全面,因为在new里还有析构,先不管这个。
    好了,我们开始分析上面的一段程序。
p2 = p1后,p2指向的地址就是p1指向的地址了。但是*p2是一个int,*P1是2个int!释放p2意味着释放&p1[0],那么为何&p1[1]也跟着释放了呢?
我有这个迷惑,也不无道理,主要是出自effective C++这样一句话
>>>>>>>>>>>>>>>******************************<<<<<<<<<<<<<<<<<<<
摘自effective C++ 条款5:
>>>>>>>>>>>>>>>******************************<<<<<<<<<<<<<<<<<<<
下面的语句有什么错?
string *stringarray = new string[100];
...
delete stringarray;
一切好象都井然有序——一个new对应着一个delete——然而却隐藏着很大的错误:程序的运行情况将是不可预测的。至少,stringarray指向的100个string对象中的99个不会被正确地摧毁,因为他们的析构函数永远不会被调用。
>>>>>>>>>>>>>>>******************************<<<<<<<<<<<<<<<<<<<
     99个不会被正确地摧毁,那么这99个会干些什么事呢?是根本没有摧毁,还是错误地摧毁。我开始钻牛角尖了.为了排除析构函数这个问题,我又写了一个测试的:
typedef struct  
{
int a;
int b;
} datatype;
//********************************
datatype * p1=new datatype;
datatype * p2=new datatype[2];
p2->a=11;
p2->b=111;
(p2+1)->a=222;
(p2+1)->b=2222;
    p1=p2;
delete p1;
    cout<<"p1->a="<<p1->a<<endl;
cout<<"p1->b="<<p1->b<<endl;
  cout<<"p2->a="<<p2->a<<endl;
cout<<"p2->b="<<p2->b<<endl;
cout<<"(p2+1)->a="<<(p2+1)->a<<endl;
cout<<"(p2+1)->b="<<(p2+1)->b<<endl;
   证明,一样被释放掉了,即它所谓的摧毁了.
结论应该很明显了。只要释放内存块的一个头,那么内存块都释放掉了。
如何解释本博文最开始的那个程序呢?
编译器出于安全考虑,他不知道是要释放P1 还是P2,干脆就大不就小,一起delete掉了。delete之后 p1自己的地址(&p1)还是没变,指向的地址(p1)还是没变,但指向的地址的值(*p1)已是不确定的,因为有可能系统把这个地址分配给了别的进程使用。
  总之,得出结论,delete p2 和delete [] p2没有区别。p1和p2指向堆上的同一个内存,不管是释放哪一个,这两个都变成野指针了。如果那位朋友如果可能解释这个问题,有自己的想法,我必定拜谢。

除了上面的一个危险操作之外,还有这个操作也非常常见,见下程序。它直接导致内存泄漏。
给p new了一个空间,但是P却赋值p1,这样一来,*P占用的是P1的前10个内存了,原来的p的内存堆丢了,成了系统垃圾,自己不用,别人也用不了。
int* p = new int[10];
int* p1 = new int[11];
p = p1;
delete p;
p = NULL;
_CrtDumpMemoryLeaks();

Detected memory leaks!
Dumping objects ->
E:\work_station\mfc_station\test18\test18Dlg.cpp(146) : {76} normal block at 0x00384D60, 40 bytes long.
Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
strcore.cpp(118) : {75} normal block at 0x00384D08, 16 bytes long.

1

主题

11

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
274
威望
237
贡献
35
兑换币
0
注册时间
2010-5-1
在线时间
1 小时
2#
 楼主| 发表于 2010-5-1 10:55:05 | 只看该作者
回复 1# we3o


   抢沙发
回复 支持 反对

使用道具 举报

3

主题

310

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1422
威望
591
贡献
617
兑换币
4
注册时间
2009-3-11
在线时间
107 小时
3#
发表于 2010-5-1 10:59:58 | 只看该作者
看得不大懂!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

关于我们|联系我们|小黑屋|智能车制作 ( 黑ICP备2022002344号

GMT+8, 2024-9-29 03:21 , Processed in 0.044342 second(s), 29 queries , Gzip On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表