我有这样的代码:

for (std::list<item*>::iterator i=items.begin();i!=items.end();i++)
{
    bool isActive = (*i)->update();
    //if (!isActive) 
    //  items.remove(*i); 
    //else
       other_code_involving(*i);
}
items.remove_if(CheckItemNotActive);

我想在更新后立即删除不活跃的项目,以避免再次浏览列表。但是如果我添加注释掉的行,当我到达i++时,我得到一个错误:“列表迭代器不可递增”。我尝试了一些在for语句中不增加的替代方法,但我不能让任何东西工作。

什么是最好的方法来删除项目,因为你正在走std::列表?


当前回答

你想做的是:

i= items.erase(i);

这将正确地更新迭代器,使其指向您删除的迭代器之后的位置。

其他回答

你需要结合Kristo的回答和MSN的回答:

// Note: Using the pre-increment operator is preferred for iterators because
//       there can be a performance gain.
//
// Note: As long as you are iterating from beginning to end, without inserting
//       along the way you can safely save end once; otherwise get it at the
//       top of each loop.

std::list< item * >::iterator iter = items.begin();
std::list< item * >::iterator end  = items.end();

while (iter != end)
{
    item * pItem = *iter;

    if (pItem->update() == true)
    {
        other_code_involving(pItem);
        ++iter;
    }
    else
    {
        // BTW, who is deleting pItem, a.k.a. (*iter)?
        iter = items.erase(iter);
    }
}

当然,最有效和超级酷®STL精明的事情应该是这样的:

// This implementation of update executes other_code_involving(Item *) if
// this instance needs updating.
//
// This method returns true if this still needs future updates.
//
bool Item::update(void)
{
    if (m_needsUpdates == true)
    {
        m_needsUpdates = other_code_involving(this);
    }

    return (m_needsUpdates);
}

// This call does everything the previous loop did!!! (Including the fact
// that it isn't deleting the items that are erased!)
items.remove_if(std::not1(std::mem_fun(&Item::update)));

删除只会使指向被删除元素的迭代器失效。

所以在这种情况下,删除*i后,i是无效的,你不能对它做增量操作。

你能做的是首先保存要删除的元素的迭代器,然后增加迭代器,然后删除保存的迭代器。

向后迭代避免了在要遍历的剩余元素上擦除一个元素的效果:

typedef list<item*> list_t;
for ( list_t::iterator it = items.end() ; it != items.begin() ; ) {
    --it;
    bool remove = <determine whether to remove>
    if ( remove ) {
        items.erase( it );
    }
}

PS:看看这个,例如,关于向后迭代。

PS2:我没有彻底测试它是否处理好擦除元素在结束。

你想做的是:

i= items.erase(i);

这将正确地更新迭代器,使其指向您删除的迭代器之后的位置。

你必须先增加迭代器(使用i++),然后删除前一个元素(例如,通过使用i++的返回值)。你可以像这样将代码更改为while循环:

std::list<item*>::iterator i = items.begin();
while (i != items.end())
{
    bool isActive = (*i)->update();
    if (!isActive)
    {
        items.erase(i++);  // alternatively, i = items.erase(i);
    }
    else
    {
        other_code_involving(*i);
        ++i;
    }
}