【问题标题】:removing object pointer from stl list从 stl 列表中删除对象指针
【发布时间】:2013-12-31 08:08:58
【问题描述】:

考虑以下导致访问冲突的代码:

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)-&gt;isActive()) 导致异常。

我是使用列表的新手,需要一些帮助。指向的对象在其他地方管理,所以我不希望它们被破坏,只从列表中删除,不会导致此异常

【问题讨论】:

  • 你检查过指针是否有效吗?
  • 删除似乎工作得很好,但是列表中删除了一个条目,它崩溃了

标签: c++ stl


【解决方案1】:

由于您已经有了要从列表中删除的元素的迭代器,因此不应使用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 的回答展示了如何使用标准算法而不完全使用循环来做到这一点。

【讨论】:

  • 谢谢。我选择了这个,因为我不必在其他地方定义函数才能工作,但我真的希望我可以将几个答案标记为已接受。为大家点赞和感谢!
【解决方案2】:

最好的办法是将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(); });

【讨论】:

  • 这是 C++11 吗? +1;很可爱。
  • @Bathsheba 我认为它也是 C++03。
  • @juanchopanza 我可以确认它在 C++03 中工作:coliru.stacked-crooked.com/a/f293eacc0774cddb.
  • @rightfold 谢谢。我以前肯定用过它,只是我不能 100% 确定它不是编译器扩展。
  • @IanYoung 在任何函数之外定义它。
【解决方案3】:

这是经典的迭代器失效恐怕。

m_Projectiles.remove((*it)); 无效 it。由for 循环完成的it++ 执行将为您提供未定义的行为。那你的处境确实很糟糕。

一个粗略的解决方案是使用

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。重构以适应生产代码。我在这里所做的是将迭代器推进到一个安全节点,然后再删除我不再需要的那个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-20
    • 2020-11-19
    • 2014-08-03
    • 1970-01-01
    • 2017-11-17
    • 2014-04-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多