我有代码看起来像这样:
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);
Run Code Online (Sandbox Code Playgroud)
我想在更新后立即删除非活动项目,以避免再次走过列表.但是如果我添加注释掉的行,当我到达时会出现错误i++:"List iterator not incrementable".我尝试了一些替代品,它们没有在for语句中增加,但我无法得到任何工作.
当你走std :: list时,删除项目的最佳方法是什么?
Mic*_*fik 272
您必须首先递增迭代器(使用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;
}
}
Run Code Online (Sandbox Code Playgroud)
MSN*_*MSN 127
你想做:
i= items.erase(i);
Run Code Online (Sandbox Code Playgroud)
这将正确地更新迭代器以指向您删除的迭代器后的位置.
Mik*_*ike 22
您需要结合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);
}
}
Run Code Online (Sandbox Code Playgroud)
当然,效率最高的SuperCool®STLsavy就是这样的:
// 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)));
Run Code Online (Sandbox Code Playgroud)
Myk*_*yev 10
使用std :: remove_if算法.
编辑: 使用集合应该像:1.准备集合.2.流程收集.
如果你不混合这些步骤,生活会更容易.
我总结了一下,这里是三个方法的例子:
while循环list<int> lst{4, 1, 2, 3, 5};
auto it = lst.begin();
while (it != lst.end()){
if((*it % 2) == 1){
it = lst.erase(it);// erase and go to next
} else{
++it; // go to next
}
}
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
Run Code Online (Sandbox Code Playgroud)
remove_if在列表中使用成员函数:list<int> lst{4, 1, 2, 3, 5};
lst.remove_if([](int a){return a % 2 == 1;});
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
Run Code Online (Sandbox Code Playgroud)
std::remove_if函数结合erase成员函数:list<int> lst{4, 1, 2, 3, 5};
lst.erase(std::remove_if(lst.begin(), lst.end(), [](int a){
return a % 2 == 1;
}), lst.end());
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
Run Code Online (Sandbox Code Playgroud)
forloop ,要注意更新迭代器:list<int> lst{4, 1, 2, 3, 5};
for(auto it = lst.begin(); it != lst.end();++it){
if ((*it % 2) == 1){
it = lst.erase(it); erase and go to next(erase will return the next iterator)
--it; // as it will be add again in for, so we go back one step
}
}
for(auto it:lst)cout<<it<<" ";
cout<<endl; //4 2
Run Code Online (Sandbox Code Playgroud)
小智 5
Kristo 答案的替代 for 循环版本。
你失去了一些效率,你在删除时向后然后再次向前,但作为额外的迭代器增量的交换,你可以在循环范围内声明迭代器,并且代码看起来更清晰。选择什么取决于当下的优先事项。
答案完全不合时宜,我知道......
typedef std::list<item*>::iterator item_iterator;
for(item_iterator i = items.begin(); i != items.end(); ++i)
{
bool isActive = (*i)->update();
if (!isActive)
{
items.erase(i--);
}
else
{
other_code_involving(*i);
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个使用for循环的示例,该循环在列表遍历期间被删除的情况下迭代列表并递增或重新验证迭代器。
for(auto i = items.begin(); i != items.end();)
{
if(bool isActive = (*i)->update())
{
other_code_involving(*i);
++i;
}
else
{
i = items.erase(i);
}
}
items.remove_if(CheckItemNotActive);
Run Code Online (Sandbox Code Playgroud)