从stl列表中删除对象指针

时间:2013-12-31 08:08:59

标签: c++ stl

请考虑以下代码,这会导致访问冲突:

for(std::list<ProjectileNode*>::iterator it = m_Projectiles.begin(); it!=m_Projectiles.end(); it++)
{
    if(!(*it)->isActive()) //isActive returns a bool
    {
        m_Projectiles.remove((*it));
    }
}

if(!(*it)->isActive())导致异常。

我是新手使用列表,可以使用一些帮助。指向对象在其他地方进行管理,因此我不希望它们被销毁,只是从列表中删除,而不会导致此异常

3 个答案:

答案 0 :(得分:9)

由于您已经有要从列表中删除的元素的迭代器,因此不应使用remove(),因为这会再次搜索该元素。相反,使用erase(),它还返回一个指向擦除元素之后的迭代器。

这导致经典的“擦除一些元素”循环,如下所示:

for(std::list<ProjectileNode*>::iterator it = m_Projectiles.begin(); it != m_Projectiles.end(); /*increment in body*/)
{
    if(!(*it)->isActive()) //isActive returns a bool
    {
        it = m_Projectiles.erase(it);
    }
    else
    {
        ++it;
    }
}

当然,@ juanchopanza的答案显示了如何使用标准算法完全不使用循环。

答案 1 :(得分:7)

您最好的选择是使用std::list::remove_if和合适的谓词:

bool pred(const ProjectileNode* p) { return !p->isActive(); }

m_Projectiles.remove_if(pred);

或者,在C ++ 11中,

m_Projectiles.remove_if([](const ProjectileNode* p)
                        { return !p->isActive(); });

答案 2 :(得分:3)

这是经典的迭代器失效我很害怕。

m_Projectiles.remove((*it)); 无效 itit++循环执行的for执行将为您提供未定义的行为。那你确实处在一个不好的地方。

原始解决方案是使用

if (!(*it)->isActive()){
    std::list<ProjectileNode*>::iterator new_it = it;
    ++new_it; /*I prefer this to new_it++*/
    m_Projectiles.remove((*it));
    it = new_it;
} else {
   ++it;
}

作为if语句的正文并删除 it++循环中的for。重构生产代码。我在这里做的是将迭代器推进到安全节点,然后删除我不再需要的那个。