背景:
CCArray是cocos2d-x提供的非常好用一个容器类,为了方便对遍历容器里面的元素,2dx提供了CCARRAY_FOREACH这样的宏。
问题引入:
现在在做的一个塔防项目,恶魔打天使,每一个天使都存放在一个CCArray对象m_pMonsterArray中。在一个schedue中判断,当天使死掉后,就从m_pMonsterArray中删除。代码想当然的写成如下:
一开是没仔细注意看,然后看结果好像也是对的。后来为了定位另外一个问题,加了一些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中找到它的定义
这里采用了指针移动的方式来提高效率。看到这个,大概心里有个数了,因为在array中删除了一个元素,如果这个元素后面的所有元素指针都“向前移动一次”,那么就会导致这种情况。为了确认这个想法,继续看CCArray的removeObject方法,一路追下去,其最终调用了support/data_support/ccArray.cpp中的ccArrayRemoveObjectAtIndex函数。
确实,在移除需要移除的元素后,其后的所有元素都“向前移动一次”。
因此,在CCARRAY_FOREACH中进行removeObject是一种非常不安全的操作,可能导致漏删,或者导致数组越界(用CCARRAY_FOREACH为下溢,用CCARRAY_FOREACH_REVERSE为上溢)。
解决方案:
我用了一个比较笨的解决方案,先在CCARRAY_FOREACH中将所有需要删除的元素放在一个临时CCAarry对象中,然后再遍历该临时CCArray,从m_pMonsterArray中删除,代码如下:
相关推荐
改进了linux tailq队列下在遍历时删除多个元素的问题。可以使用TAILQ_FOREACH_SAFE下面进行节点删除操作。不会出现野指针问题
js_foreach_exercice2
几个不错的json中文教程,希望可以带大家入门,描述就这么多吧,没啥说的类,但字数不够上传不了,所以还得写
CCARRAY_FOREACH(play_bullet, bullets) { UnitSprite *bullet = dynamic_cast*>(bullets); if (this->collide(enemy, bullet)) { enemy->hurt(); bullet->hurt(); } if (!(m_screenRec.intersectsRect...
Boost程序库探秘 深度解析C++准标准库第2版(251-500)
超全面javaweb教程28天第11,12天_7_forEach中的循环状态变量
PHP 数组 for foreach 循环 array_column函数.rar
超全面javaweb教程28天第11,12天_6_forEach标签1
Nodejs 数组的队列以及forEach的应用详解 本文主要记录了在Nodejs开发过程中遇到过的由数组特性引起的问题及解决方式,以及对数组的灵活应用。 本文代码测试结果均基于node v6.9.5 数组与队列 利用数组对象方法...
ForEach_java(cusTag).txt,ForEach_java(cusTag).txt
foreach和array的应用(VB6.0代码编写) foreach和array的应用 QQ223857666勾月
主要给大家介绍了关于C#并发实战记录之Parallel.ForEach使用的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用C#具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
.
.
foreach和array的应用程序,请输入要查找的数字和查找结果(VB6.0源代码编写) Option Base 1 Dim A As Variant Private Sub cmdGo_Click() s_num = Val(txtInput.Text) For j = 1 To UBound(A) If A(j) = s_num ...
主要介绍了php中使用in_array() foreach array_search() 查找数组是否包含时的性能对比,需要的朋友可以参考下
var forEach = (function(){ //数组与伪数组的遍历 var _Array_forEach = function (array, block, context) { if (array == null) return; //对String进行特殊处理 if(typeof array == 'string'){ array = ...
C-FOREACH用法需要遍历的集合放到items中,然后定义一个temp为每次应用到的集合元素,然后设置起步值及叠加步数
对对Foreach语句测试