Safely removing duplicates from CCArray


#1

cocos2d-x 2.1.5
host: ubuntu 12.04
target: Blackberry 10

I have a CCArray containing subclassed CCSprites. If two (or more) of these sprites are in the same location I want to remove them from the array.

But my naive attempt at doing this…

CCARRAY_FOREACH(_sprites, it) {
  mysprite* sprite1 = dynamic_cast(it);
  CCARRAY_FOREACH(_sprites, jt) {
    if (it == jt)
      continue;
    mysprite* sprite2 = dynamic_cast(jt);
    if (sprite2->row == sprite1->row && sprite2->col == sprite1-col) {
      _sprites->removeObject(sprite2);
      this->removeChild(sprite2, true);
    }
  }
  _sprites->removeObject(sprite);
  this->removeChild(sprite, true);
}

…occasionally blows up with a segfault. I think this is because removing an object reindexes the array messing up the foreach loop. Is this correct? Then how should I do this?

Added difficulty. g*+ 4.6.3 on blackberry only partially supports c*+11 it seems so I don’t know if I can use STL algorithms.

All help gratefully accepted.


#2

I find that when I want to alter an array while iterating, going backwards using a for loop works well

  for ( int i = (myArray->count() - 1); i >= 0; i-- )
  {
    ... your code goes here ...
    if ()  myArray->removeObjectAtIndex(i);
  }

#3

CCARRAY_FOREACH is not noted as being safe for use when removing elements

Some ideas

  1. note the indexes you want to remove in a different collection, and remove those in a second “remove [set] nodes” loop

  2. consider a different collection type. CCDICT_FOREACH allows element removal.

probably a lot of other ways, those are the 2 i thought of.

/** The macro for traversing dictionary
 *  
 *  @note It's faster than getting all keys and traversing keys to get objects by objectForKey.
 *        It's also safe to remove elements while traversing.
 */
#define CCDICT_FOREACH(__dict__, __el__) \
    CCDictElement* pTmp##__dict__##__el__ = NULL; \
    HASH_ITER(hh, (__dict__)->m_pElements, __el__, pTmp##__dict__##__el__)