CCARRAY_FOREACH应用误区

背景:

CCArray是cocos2d-x提供的非常好用一个容器类,为了方便对遍历容器里面的元素,2dx提供了CCARRAY_FOREACH这样的宏。

问题引入:

现在在做的一个塔防项目,恶魔打天使,每一个天使都存放在一个CCArray对象m_pMonsterArray中。在一个schedue中判断,当天使死掉后,就从m_pMonsterArray中删除。代码想当然的写成如下:

code_segment1

一开是没仔细注意看,然后看结果好像也是对的。后来为了定位另外一个问题,加了一些log信息,才发现这段代码隐藏的bug。

问题定位:

为了方便调试,将所有monster的HP都设置为0,预期只要执行一次上面的代码,m_pMonsterArray就应该被清空。但是实际上第一轮没执行完,就已经报了”std::__non_rtti_object at memory location 0x003EF430″的错误,打印出来的log如下:

Add monster, uid=78
Add monster, uid=79
Add monster, uid=80
Add monster, uid=81
Add monster, uid=82
Add monster, uid=83
Add monster, uid=84
Add monster, uid=85
Add monster, uid=86
Add monster, uid=87

******************
The 1 times calling update
Clear monster, uid=78
Clear monster, uid=80
Clear monster, uid=82
Clear monster, uid=84
Clear monster, uid=86
Clear monster, uid=87

从log中可以看出,删除的时候是隔一个删一个,与我们便利array中所有元素的初衷相差甚远,所以,一定是什么地方用错了。

首先仔细看看CCARRAY_FOREACH这个宏,可以在cocoa/CCArray.h中找到它的定义

CCARRAY_FOREACH

这里采用了指针移动的方式来提高效率。看到这个,大概心里有个数了,因为在array中删除了一个元素,如果这个元素后面的所有元素指针都“向前移动一次”,那么就会导致这种情况。为了确认这个想法,继续看CCArray的removeObject方法,一路追下去,其最终调用了support/data_support/ccArray.cpp中的ccArrayRemoveObjectAtIndex函数。

CCARRAY_MOVE

确实,在移除需要移除的元素后,其后的所有元素都“向前移动一次”。

因此,在CCARRAY_FOREACH中进行removeObject是一种非常不安全的操作,可能导致漏删,或者导致数组越界(用CCARRAY_FOREACH为下溢,用CCARRAY_FOREACH_REVERSE为上溢)。

解决方案:

我用了一个比较笨的解决方案,先在CCARRAY_FOREACH中将所有需要删除的元素放在一个临时CCAarry对象中,然后再遍历该临时CCArray,从m_pMonsterArray中删除,代码如下:

修改后截图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值