中级会员
- 积分
- 274
- 威望
- 237
- 贡献
- 35
- 兑换币
- 0
- 注册时间
- 2010-5-1
- 在线时间
- 1 小时
|
堆、栈、静态全局区、常量区、代码区我就不介绍了,这些是先备知识。
大家可以去百度搜很多相关的文章。包括内存的申请方式,系统响应,编译区别,优缺点,以及各种内存占用的实质等等。
由于前段时间给公司写的程序构架有些乱,后来终于出了问题。事情源于这个程序,(当然简化了很多)。
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. |
|