std :: list удаление элементов, вызывающих проблемы - PullRequest
1 голос
/ 11 января 2012

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

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

Мои выводы:

Это создает проблему, когда: в списке более 2 элементов и «снаряд», который был добавлен в список раньше, чем снаряд, добавлено позже "удаляется этим методом.

Нет проблем, когда: В списке только один элемент ИЛИ Все элементы удаляются одновременно.

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

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

Ответы [ 2 ]

2 голосов
/ 11 января 2012

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

1 голос
/ 11 января 2012

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

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

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

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

...