2012-03-14 64 views
0

我在这里有一个奇怪的问题。我试图从粒子系统中删除一个迭代器(std :: list)。当粒子离开屏幕时,我擦除迭代器。当我在调试模式下检查粒子的大小时,发现它们是释放模式的两倍,我不知道为什么。在调试和释放模式中从列表中删除迭代器?

请找到下面的代码

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++; 
} 
+0

如何检查在发行规模? – 2012-03-14 13:12:22

+0

我看到速度取决于实时,这意味着它取决于帧速率。这通常会在发布和调试之间导致不同的行为。它可能是如此简单的事情吗? – Agentlien 2012-03-14 13:14:54

+0

@izomorphius我只是cout << m_Particles.size(); – 2012-03-14 13:16:56

回答

2

两点:

  1. 你应该使用p->m_Targets.erase(t);而非p->m_Targets.remove(*t)。特别是,由于您使用的是remove(),它取值,std :: list类必须扫描整个列表才能找到您指定的值。

  2. 从列表中删除元素会使指向该元素的任何迭代器失效。所以你的t迭代器会失效。使用无效的迭代器具有未定义的行为。幸运的是,它(相对)很容易解决。尝试是这样的:

    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); 
        } 
    } 
    

请注意,我们只能做“++ T”如果我们不通过循环删除在每个迭代上的元素(和,因为你没有你的for循环)。

你的外循环中有类似的错误。替换此:

 if(p->m_bIsDead) 
     { 
      p = m_Particles.erase(p); 
     } 
     p++; 

与此:

 if(p->m_bIsDead) 
      p = m_Particles.erase(p); 
     else 
      ++p; 
+0

感谢您的回复。 它有相同的性能问题,使用您的建议。 怎么样的行: 如果(对 - > m_bIsDead) \t \t { \t \t \t P = m_Particles.erase(P); \t \t \t // std :: cout <<“particle sizes”<< m_Particles.size()<< std :: endl; \t \t \t \t} – 2012-03-14 14:16:58

+0

@AhmedSaleh:更新响应描述错误的外环,而事实上,你不应该增加你的迭代器,如果你只是删除了一个元素,因为那样会导致你跳过的元素。 – 2012-03-14 14:57:56

+0

此行编译失败 t = p-> m_Targets.remove(t); 我甚至用过 t = p-> m_Targets.erase(t); 它崩溃 – 2012-03-14 16:09:59

相关问题