Reputation: 1891
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++;
}
Upvotes: 0
Views: 199
Reputation: 15944
Two points:
You should use p->m_Targets.erase(t);
rather than p->m_Targets.remove(*t)
. In particular, since you're using remove()
, 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 t
iterator is getting invalidated. Using an invalid iterator has undefined behavior. Luckily, it's (relatively) easy to solve. Try something like this:
std::list<Target>::iterator t = m_Targets.begin();
while (t != m_Targets.end())
{
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();
}
++t;
}
else
{
t = p->m_Targets.erase(t);
}
}
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:
if( p->m_bIsDead )
{
p = m_Particles.erase(p);
}
p++;
with this:
if( p->m_bIsDead )
p = m_Particles.erase(p);
else
++p;
Upvotes: 2