慎用CCARRAY_FOREACH
来源:互联网 发布:算法必须有输出 编辑:程序博客网 时间:2024/06/06 08:28
使用CCARRAY_FOREACH遍历一个CCArray数组并且删除数组里的东西时发生出乎意料的结果:
这段代码执行下来,发现有些Tag为1的精灵没有被删除,为了查原因,我追查到CCARRAY_FOREACH宏的定义中:
如果在我原来的代码中展开CCARRAY_FOREACH宏的话,代码为如下形式:
类似代码如下:
CCArray *children = this->getChildren();CCObject *temp = NULL;CCARRAY_FOREACH(children, temp){ CCSprite *sprite = dynamic_cast<CCSprite*>(temp); if(sprite->getTag() == 1) { this->removeChild(sprite); }}
这段代码执行下来,发现有些Tag为1的精灵没有被删除,为了查原因,我追查到CCARRAY_FOREACH宏的定义中:
#define CCARRAY_FOREACH(__array__, __object__) \ if ((__array__) && (__array__)->data->num > 0) \ for(CCObject** __arr__ = (__array__)->data->arr, **__end__ = (__array__)->data->arr + (__array__)->data->num-1; \ __arr__ <= __end__ && (((__object__) = *__arr__) != NULL/* || true*/); \ __arr__++)
如果在我原来的代码中展开CCARRAY_FOREACH宏的话,代码为如下形式:
if ((children && children->data->num > 0) for(CCObject** __arr__ = children->data->arr, **__end__= children->data->arr + children->data->num-a; __arr__ <= __end__ && (((temp) = *__arr__) != NULL); __arr__++){ CCSprite *sprite = dynamic_cast<CCSprite*>(temp); if(sprite->getTag() == 1) { this->removeChild(sprite); }}
然后追踪到void CCNode::removeChild(CCNode* child)->
void CCNode::removeChild(CCNode* child, bool cleanup)->
void CCNode::detachChild(CCNode *child, bool doCleanup)->
最后定位到detachChild中的m_pChildren->removeObject(child);是关键
m_pChildren是一个CCNode中的一个CCArray类型变量,CCArray中调用removeObjectsInArray又调用了ccArray类中的ccArrayRemoveArray函数,最终定位到ccArrayRemoveObjectAtIndex中的memmove((void *)&arr->arr[index], (void *)&arr->arr[index+1], remaining * sizeof(CCObject*));
memmove函数中把CCArray中当前要删的那个项删掉,然后后面的项往前移动,所以当有两个连续的项Tag为1的精灵为A、B,并且当前的__arr__指向A精灵,当把当前__arr__指向的精灵(A精灵)删掉后,同时也执行了把后面B精灵往前移动了,所以本轮循环结束后,执行__arr__++后,__arr__指向的是B精灵后面的精灵的地址,所以B精灵成为了漏网之鱼。
结论:不要在CCARRAY_FOREACH遍历CCArray时删除里面存的对象。但是可以用CCARRAY_FOREACH_REVERSE宏,因为这个宏是从后面遍历的。
0 0
- 慎用CCARRAY_FOREACH
- 慎用CCARRAY_FOREACH
- 慎用CCARRAY_FOREACH
- CCARRAY_FOREACH
- 慎用!
- 慎用""
- CCARRAY_FOREACH应用误区
- CCARRAY_FOREACH和CCARRAY_FOREACH_REVERSE
- Cocos2d-x中的CCARRAY_FOREACH的使用
- 慎用AXIS2
- 慎用@@IDENTITY
- 慎用strip
- 慎用TerminateThread
- 慎用IEquatable
- 慎用sendmessage
- 慎用USES_CONVERSION
- 慎用线程
- 全局变量慎用
- debian7下eclipse4.4无法启动
- git clone "error: RPC failed; result=18, HTTP code = 200 "
- 面向对象的认识----类的转化
- 在MFC中捕获CWebBrowser控件的事件
- Hadoop HA(高可用)配置
- 慎用CCARRAY_FOREACH
- 进程和线程的区别
- Java中JOptionPane的用法
- 黑马程序员——数组
- 《思考的乐趣》读书笔记
- 在MFC应用中深入定制WebBrowser控件
- 软考——(2)数据结构
- Matlab基础学习--------关系和逻辑运算及多项式运算
- java之Io-File类