I have a strange problem here. I’m trying to erase an iterator from a particle system (std::list). I erase an iterator when the particles goes out of screen. When I checked the size of the particles in debug mode, I found that they are the double compared to release mode, I don’t know why.
Kindly find the following code
void ParticleManager::update(std::vector<ci::Vec2f> masses)
{
int targetDifference = masses.size() - m_Targets.size();
if (masses.size() == 1 && targetDifference == 1)
{
addTarget();
}
else if (targetDifference > 1)
{
addTarget();
}
else if (targetDifference < 0)
{
deleteTarget();
}
Vec2f currVec, offset;
float fCurrLengthSquared;
bool bAllTargetsActive = true;
std::list<Particle>::iterator p = m_Particles.begin();
while( p != m_Particles.end() )
{
p->update();
float fMinSquaredLength = 0.0f;
// influence of the masses
for( int i = 0; i < (int) masses.size(); ++i )
{
currVec = masses[i] - p->m_Position;
fCurrLengthSquared = currVec.lengthSquared();
if (fCurrLengthSquared < ParamMgr.m_fForceMinDist * ParamMgr.m_fForceMinDist)
{
fCurrLengthSquared = ParamMgr.m_fForceMinDist * ParamMgr.m_fForceMinDist;
}
if(fCurrLengthSquared < ParamMgr.m_fForceMaxDist * ParamMgr.m_fForceMaxDist)
{
offset = currVec.normalized() / (fCurrLengthSquared / 500.0f); // 1000.0f
p->m_Direction += offset * ((float) TimerMgr.getDeltaTime() * ParamMgr.m_fGravity * ParamMgr.m_fGravity );
}
/*if( i == 0 )
fMinSquaredLength = fCurrLengthSquared;
if( fCurrLengthSquared < fMinSquaredLength )
fMinSquaredLength = fCurrLengthSquared;*/
}
if( masses.size() > 0 )
{
float fSquareColorRadius = ParamMgr.m_fColorRadius * ParamMgr.m_fColorRadius;
if( fMinSquaredLength > fSquareColorRadius )
fMinSquaredLength = fSquareColorRadius;
float fIntensity = 1.0f - (fMinSquaredLength / fSquareColorRadius) * 0.9f;
//p->m_Color = ci::Color(0.0f, fIntensity, 0.0f);
//p->m_Color = ci::Color(0.0f, 1.0f, 0.0f);
}
p->m_fAge += (float) TimerMgr.getDeltaTime();
// outside the window
if( p->m_Position.x < 0.0f - m_fCollisionOffsetX || p->m_Position.x > getWindowWidth() + m_fCollisionOffsetX ||
p->m_Position.y < 0.0f - m_fCollisionOffsetY || p->m_Position.y > getWindowHeight() + m_fCollisionOffsetY )
{
p->m_bIsDead = true;
}
else
{
// check targets
for( std::list<Target>::iterator t = m_Targets.begin(); t != m_Targets.end(); t++ )
{
if( t->checkParticle( p->m_Position ) )
{
p->m_ColorChange = Color( CM_HSV, t->m_fHue, t->m_fSat * 0.9f, 1.0f );
if( p->checkTarget( *t ) )
{
t->addParticleHit();
}
}
else
{
if( t != m_Targets.end() )
{
p->m_Targets.remove( *t );
//std::cout << "Try to erase: " << (*t).m_Position << " from target list." << std::endl;
}
}
}
}
if( p->m_bIsDead )
{
p = m_Particles.erase(p);
}
p++;
}
Two points:
You should use
p->m_Targets.erase(t);rather thanp->m_Targets.remove(*t). In particular, since you’re usingremove(), which takes a value, the std::list class must scan through the entire list to find the value you specify.Removing an element from a list invalidates any iterators that point at that element. So your
titerator is getting invalidated. Using an invalid iterator has undefined behavior. Luckily, it’s (relatively) easy to solve. Try something like this:Note that we only do “++t” if we don’t remove an element (and not on every iteration through the loop, as you did with your for loop).
There’s a similar bug in your outer loop. Replace this:
with this: