2012-01-11 4 views
1

Я пытался отладить это почти полдня, и я просто не могу найти проблему. Скорее всего, что вызывает проблемы этот метод:std :: list удаление элементов, вызывающих проблемы

//[datamember]  
std::list<Projectile*> m_Projectiles_l; 

//[predicate]  
bool removeDeads(Projectile* pProj) { 
    return !(pProj->isAlive()); 
} 

//[the method I think might be causing the problem] 
void ProjectileList::KillDeadProjectiles() 
{ 
    std::list<Projectile*>::iterator it; 
    it = std::remove_if(m_Projectiles_l.begin(), m_Projectiles_l.end(), &removeDeads); 

    if (it != m_Projectiles_l.end()) 
    { 
     std::list<Projectile*>::iterator itDelete; 
     for (itDelete = it; itDelete != m_Projectiles_l.end(); ++itDelete) { 
      delete (*itDelete); 
     } 
     m_Projectiles_l.erase(it, m_Projectiles_l.end()); 
    } 
} 

VS2010 ошибка перерыв:

Unhandled exception at 0x00389844 in PsychoBots.exe: 0xC0000005: Access violation reading location 0xfeeeff3a. 

Ломать подводит меня к этой линии:

void ProjectileList::DoPhysicsStuff(const InputState& refInputState) 
{ 
    KillDeadProjectiles(); 

    std::list<Projectile*>::iterator it; 
    for (it = m_Projectiles_l.begin(); it != m_Projectiles_l.end(); ++it) { 
/*[THIS line]*/(*it)->DoPhysicsStuff(refInputState); 
    } 
} 

Мои выводы:

It gives a problem when: there are more than 2 elements in the list, and a "projectile that has been added to the list earlier than a projectile that has been added later on" is getting removed with this method.

It gives no problems when: There is only one element in the list OR All the elements are getting removed at the same time.

Может ли кто-нибудь увидеть ошибки в этом?

Если вам нужно больше кода, прокомментируйте, я попытался сохранить его на небольшом размере.

+3

Вам не разрешено использовать итераторы после результата 'remove_if'. Вы можете их стереть, но вы не должны обращаться к ним, так как они не гарантируются в каком-либо конкретном состоянии. Потратьте на себя всю эту трату времени, и перестаньте использовать необработанные указатели. –

+0

@KerrekSB Я почти добавил к комментариям «пожалуйста, никаких комментариев о умных указателях», потому что я не могу их использовать;) Но я решил не делать этого, поскольку люди любят комментировать его. – xcrypt

ответ

2

Вы не можете положиться на содержимое контейнера за итератором, возвращаемое remove_if. Это означает, что вам придется использовать другой подход, если вы хотите управлять динамической памятью в контейнере. Простым способом является сохранение объектов shared_ptr вместо необработанных указателей. Тогда вы можете просто использовать идиому удаления-стирания, и все будет очищено. В противном случае вам понадобится тщательно написать механизм удаления самостоятельно, вместо использования remove_if.

1

Прочтите ссылку на std :: remove_if() тщательно. (http://www.cplusplus.com/reference/algorithm/remove_if/)

Значения в диапазоне от «it» до «m_Projectiles_l.end()» по-прежнему действительны, но его значения не определены. Скорее всего, эти значения не изменяются, в зависимости от реализации.

Таким образом, элемент может быть включен в новый список и по-прежнему находиться в конце старого списка. Удаление этого элемента приведет к исключению памяти.

Вы должны найти другой способ удаления элементов, не имеющих ссылки. Рассмотрим интеллектуальные указатели.

+0

Да, я должен сказать. прочитайте ссылку лучше в следующий раз :) – xcrypt

Смежные вопросы