一个要引起注意的delete动作

我在双向链表类中定义的clear()函数
如下:

void clear()

       {

              if( !isEmpty() )

              {

                     list_item< type >* temp = list_head;

                     list_item< type >* delTemp;

             

                     while( temp !=  list_tail )

                     {

                            delTemp = temp;

                            temp = temp->back;

                            delete delTemp;//释放空间

                     }

原来这里的语句是temp !=  list_tail->back 但是一旦 temp 被赋值为 list_tail->back //么它本身就是 delTemp 即将被删除的空间的一部分 再对一个已经不存在的指针进行操作当然就会崩溃 这样就导致在对temp的引用是不存在的 所以出错

                     delete list_tail;

                     list_head = NULL;

                     size = 0;

              }

              else

              {

                     return;

              }

       }

我还是很快发现了 但是很有觉得价值 所以写下提醒自己

posted on 2007-04-11 16:55 lele 阅读(1437) 评论(15)  编辑 收藏 引用

评论

# re: 一个要引起注意的delete动作 2007-04-13 12:40 anthony

不知道你之前的代码是不是只是while那里不一样,
个人感觉不是temp的问题,如果照你以前的写法,应该是是最后的delete list_tail;的问题
void clear()

{

if( !isEmpty() )

{

list_item< type >* temp = list_head;

list_item< type >* delTemp;



while( temp != list_tail->back)//你以前的写法

{

delTemp = temp;

temp = temp->back;


delete delTemp;//释放空间

}



// delete list_tail; //这句不要了,因为delTemp 总是指向temp的前一个,当temp = list_tail->back时是在最后,此时delTemp = list_tail已删除完整个链表,觉得如果你之前的语句只是while那里不一样,应该是这里出错了,不知道有没有理解你原来的意思。觉得有点疑问

list_head = NULL;

size = 0;

}

else

{

return;

}

}

  回复  更多评论   

# re: 一个要引起注意的delete动作 2007-04-14 00:09 lele

呵呵 谢谢你的疑问 我刚刚走查了一下就是我的那个问题
你可以自己试一试 当执行到delTemp指向尾节点的前一个节点时 temp指向尾节点 此时还不满足temp != list_tail->back 但是下一句是
delTemp = temp; 这句之后 temp = temp->back; 这句之后 temp满足了退出循环的条件 但是它指向了尾节点的一部分(list_tail->back )而这个list_tail->back 经过随后的一步delete delTemp;就被删除了 这样在下一次循环入口条件判断时 temp已经成了一个野指针 对它的引用当然也是不正确的

不知道这样说你清楚了吗??  回复  更多评论   

# re: 一个要引起注意的delete动作 2007-04-14 10:53 anthony

你的意思是temp=list_tail->back ;时,deltemp等于list_tail,然后删除了deltemp,相当于删了list_tail,这样我觉得应该是list_tail变成了野指针吧(其实都一样),我的想法是这样的,如果list_tail->back = NULL ,temp就变成了NULL,而应该是list_tail变成了野指针,我知道这是有点钻死胡同的感觉(因为结果是一样的),我只是把为什么我不理解你的程序的那些注释说出来而已,讨论清楚而已,你觉得是不是应该是list_tail是野指针,而不是temp?

不过说真的我光注意前面的temp了,而没注意后面的tail_back(就while的条件里面),看来以后还得注意前后  回复  更多评论   

# re: 一个要引起注意的delete动作 2007-04-14 13:31 lele

list_tail是类的成员 这个类都被释放了就不存在了 那么你说list_tail是什么?? 而temp是无关的局部变量 它在这个局部内使我控制 除了这个局部就不是我能管理的了 但是类不同 temp要使用我类中的back成员 当然得back存在啊 而我把back delete了 你说temp指向的list_tail的back是什么??  回复  更多评论   

# re: 一个要引起注意的delete动作 2007-04-14 13:32 lele

不过以后大家可以经常讨论 这是好事情 我要谢谢你的  回复  更多评论   

# re: 一个要引起注意的delete动作 2007-04-14 14:29 anthony

你的clear函数只是清空了链表的内存空间listitem,并没有删除list这个对象,对象的删除得由析构函数来执行
 

比如你执行了一个LIST Object,只是一个链表对象,往里面加item,然后clear方法Object.Clear()只是删除了里面的item的空间,而成员对象是否应该还存在?就是List_tail还是一个指针,它还有它的值,它指向它原先的内存地址,我的理解是比如List_tail现在是一个门牌号101,而item是里面的人,里面如果搬家了,执行的是Clear,但门牌号还在,而只有把房子给拆了,才是把对象给释放了,或者你可以试一下把List_tail设为公有,然后Clear()后,然后List_tail 0x16;这说明List_tail还是存在,它还指向那片内存单元,或者你跟踪一下,在执行Clear之前,看下list_tail的地址,Clear之后,在看下那地址,是不是一样的,temp也只是个指针,无论后面的list_tailback存不存在,它还是个内存中的一个编号(门牌号),如果存在,程序正确,不存在,就是野指针,个人认为只要它值为NULL它就不应该是野指针,我说的应该是list_tail是野指针,是因为当最后deltemp也指向list_tail时,temp = list_tail->back = NULL;此时由于delete deltemp

list_tail空间就不存在了,但它还指向那个地址,但是后面就没有back了,所以会出错


如果改成
 

while(temp != list_tail->back && temp != NULL), 当然这个没你的算法好,这个得多做多个判断,时间负责度比你原先的高,就是感觉要说引用了不存在的对象应该是list_tail引用了不存在的对象,你觉得呢?(个人愚见)

  回复  更多评论   

# re: 一个要引起注意的delete动作 2007-04-14 23:11 lele

temp != list_tail->back && temp != NULL这里依然有个问题就是
先判断temp != list_tail->back会出错,还是把两个语句调换一下位置
这样就能保证安全性了 呵呵
你的想法挺好的 谢谢你的想法!  回复  更多评论   

# re: 一个要引起注意的delete动作 2007-04-16 09:41 anthony

以前倒还真没注意过和顺序有关,又学到了,看来讨论真的能有意外的收获,谢谢你的指正

呵呵,听你这么一说,然后觉得是不是while(temp != NULL)就可以了?  回复  更多评论   

# re: 一个要引起注意的delete动作 2007-04-17 18:09 lele

呵呵 我都被你误导了 temp != list_tail->back 和 temp != NULL 这两局并没有区别 list_tail->back 就是NULL
List_tail指向的内容被析构之后 系统就会给List_tail分配一个我们无法得知的指向。
back不在了之后 我下一步要执行的是判断temp是不是back 你说它都没有了怎么判断呢?
你的编程想法真的很有意思。你怎么知道temp一定是NULL 那是你的机器 我的机器就不是 而且怎么可能呢? 我是在堆栈上面申请的。temp是静态的。它指向的内存被系统回收了,你怎么还可以用呢? 无论是不是NULL 只要你动用就是出错。这样编程不好 代码可以说很差 太不安全 太随意 还要依靠运气 你说呢?
  回复  更多评论   

# re: 一个要引起注意的delete动作 2007-04-17 21:45 anthony

对啊,所以你不是说要给它换个顺序变成
while(temp != NULL && temp != list_tail->back )吗?这样不就安全了吗?

如果你是这个意思,下面的就别看了,这样不就安全了吗?还能有什么问题吗?

可能我理解NULL有问题,我觉得NULL就相当于一个const变量,它永远指向内存中的一个不存在的地方,“ list_tail->back 就是NULL ”没错,然后当temp指向list_tail时,然后根据while(temp!=NULL)进入循环体,接着deltemp就指向了list_tail,然后temp = temp_back,就是此时,
temp=NULL,然后删除了list_tail,然后判断时,temp不是等于NULL了吗?然后循环条件成立不了,

我的理解是NULL是指向一个相当于CONST的地址空间,不管list_tail有没有,我们都可以指向NULL,NULL和list_tail 没关吧?

还有说的“List_tail指向的内容被析构之后 系统就会给List_tail分配一个我们无法得知的指向”,我觉得它还是指向原来那个地方吧?

我观察了下面的代码

int *p = NULL;//此时p指向0x00000000
p = new int [200];//此时p指向0x00441ac0
delete p;
cin>>a;//此时p还指向0x00441ac0


然后还有
temp != list_tail->back 和 temp != NULL

对于前面的节点时它们是一样的,但在最后那个点时,即deltemp = list_tail时,然后temp = temp->back(就是NULL)了,然后系统把list_tail删了,然后list_tail还指向那个系统单元(就是只是系统把房子里的人赶了出去,但门牌号还是那个),然后再进入循环条件,然后此时list_tail->back 引用就会出错了,因为list_tail里面已经没“人”了,在加一个back相当里面的一个人,所以会出错,

不知道你能否明白我的意思,或者可能我没明白你的意思,还有一个就是NULL的问题,就是temp的指向的内容被回收,但它还是可以指向地址,现在就是指向NULL,只要temp!=NULL,只是判断temp的数值而已,呵呵,写着写着就变很罗嗦了,呵呵   回复  更多评论   

# re: 一个要引起注意的delete动作 2007-05-09 00:41 lele

呵呵 这段时间有事离开了
我的意思就是感觉编程不能碰运气,还是以安全为上是好习惯
走查会根据编译器不同而分配给你用的内存的初始内容不同。谁也不能控制。  回复  更多评论   

# re: 一个要引起注意的delete动作 2007-05-12 10:14 anthony

呵呵,同意编程不能靠运气。
 
可能我水平太低吧,不能理解指针的真正含义?也不能理解你的意思。
 
我实在不明白list_tail->back=null,然后temp=list_tail->back,然后temp不是指向了null吗?对于一个指针我觉得可以对它进行任何赋值,然后temp!=null只是拿存放指针本身的那块内存里面的数值去和0X0000000内存地址比较,即使指向的内容被析构了,但指针它同样占着它的内存空间,拿temp和null比只是存放temp指针那块内存里面的数值和null比,不是存放temp指针的那块内存里面的数值指向的内存,怎么会出错呢?
 
不过你的代码看起来真的很舒服,不知道你是怎么做到的,就是我写的时候缩排格式,我也一直在注意,按照《高质量程序设计指南 C++/C语言》 上面的写法来写的,但还是感觉有点乱,是不是注释写得太多会显得乱呢?这方面得向你请教,呵呵
  回复  更多评论   

# re: 一个要引起注意的delete动作 2007-06-07 14:25 lele

问题不是出在temp是出在list_tail->back
list_tail对back的操作
back已经被释放了,不可再访问

呵呵 我水平很一般,前几天ACM亚洲银奖的同学敲代码,半小时做三道题,我都崩溃了……
慢慢来吧,总是天外有天的。  回复  更多评论   

# re: 一个要引起注意的delete动作 2007-07-26 11:35 anthony

list_tail->back不就是null吗?它没有指向哪个对象,只是指向null那个地址0x00000000,而已,null就是0x00000000,没有指向哪个对象,呵呵,

好长时间没过来了,不知道你是否也还记得你所写的,和我们讨论的,我刚是从头到尾又看了编。

acm亚洲银奖?那很厉害的,同时呢我也参加过acm,也见过好多acm的同学的代码,还有网上的一些比较厉害的人的代码,因为他们追求的是速度,不管是算法效率,还是敲程序的速度,所以我看过的acm代码的风格没有你写得好,我还记得我那时候见他们敲字得速度,惊讶得说不出话来了,呵呵  回复  更多评论   

# re: 一个要引起注意的delete动作 2007-07-26 11:53 anthony



哈哈,抱歉,终于知道我哪里出问题了,你看下是不是这里:

# re: 一个要引起注意的delete动作 2007-04-17 18:09 lele
呵呵 我都被你误导了 temp != list_tail->back 和 temp != NULL
这两局并没有区别 list_tail->back 就是NULL


在list_tail没被删除前,这两句的确是一样的,可list_tail->back被删后,这就不一样了,因为temp没有引用->back,而list_tail引用了back,而list_tail被删除了,所以不能引用list_tail->back,而就像你前面告诉我的

# re: 一个要引起注意的delete动作 2007-04-14 23:11 lele
temp != list_tail->back && temp != NULL这里依然有个问题就是
先判断temp != list_tail->back会出错,还是把两个语句调换一下位置
这样就能保证安全性了 呵呵




还是你提醒了我

# re: 一个要引起注意的delete动作 2007-06-07 14:25 lele
问题不是出在temp是出在list_tail->back
list_tail对back的操作
back已经被释放了,不可再访问


你是不是敲错了,是list_tail被释放了??呵呵



谢谢你的指点啊,经过这样讨论,我觉得应该对指针和链表的认识又进一步了,谢谢你啊,呵呵  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2007年4月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

导航

统计

常用链接

留言簿(1)

随笔档案

文章档案

搜索

最新评论

阅读排行榜

评论排行榜