你可以从一个std ::列表中删除元素,而迭代通过它?
我有这样的代码:
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++
时出现错误:“List iterator not incrementable”。 我尝试了一些在for语句中没有增加的替代项,但是我没有得到任何工作。
当你走std :: list时,删除项目的最好方法是什么?
你必须先增加迭代器(用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; } }
你想做:
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 != items.end()) { item * pItem = *iter; if (pItem->update() == true) { other_code_involving(pItem); ++iter; } else { // BTW, who is deleting pItem, aka (*iter)? iter = items.erase(iter); } }
当然,最有效率的和SuperCool®STL savy的东西会是这样的:
// 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)));
使用std :: remove_if算法。
编辑:与收藏工作应该是:1.准备收集。 2.过程收集。
生活会更容易,如果你不会混合这个步骤。
- 的std ::的remove_if。 或list :: remove_if(如果你知道你使用list而不是TCollection)
- 的std :: for_each的
循环版本替代克里斯托的答案。
你失去了一些效率,你回去,然后在删除时再次转发,但作为交换额外的迭代器增量,你可以让迭代器在循环范围中声明,代码看起来更干净。 要选择什么取决于当前的优先事项。
答案完全没有时间,我知道…
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); } }
下面是一个使用for
循环的例子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);
删除只会使指向被删除元素的迭代器失效。
所以在这种情况下,删除*我后,我是无效的,你不能做增量。
你可以做的是首先保存要删除的元素的迭代器,然后递增迭代器,然后删除保存的元素。
你可以写
std::list<item*>::iterator i = items.begin(); while (i != items.end()) { bool isActive = (*i)->update(); if (!isActive) { i = items.erase(i); } else { other_code_involving(*i); i++; } }
你可以使用std::list::remove_if
编写等价的代码,这个代码不那么冗长,也没有更明确的
items.remove_if([] (item*i) { bool isActive = (*i)->update(); if (!isActive) return true; other_code_involving(*i); return false; });
应该使用std::vector::erase
std::remove_if
成语时,项目是一个向量而不是一个列表,以保持竞争力在O(n) – 或者如果你写的泛型代码和项目可能是一个没有有效的容器擦除单个项目的方法(如向量)
items.erase(std::remove_if(begin(items), end(items), [] (item*i) { bool isActive = (*i)->update(); if (!isActive) return true; other_code_involving(*i); return false; }));
如果你像队列一样考虑std::list
,那么你可以将所有你想要保留的项目出队并排入队列,但是只会出队(而不是入队)你想要删除的项目。 这里是一个例子,我想从包含数字1-10的列表中删除5 …
std::list<int> myList; int size = myList.size(); // The size needs to be saved to iterate through the whole thing for (int i = 0; i < size; ++i) { int val = myList.back() myList.pop_back() // dequeue if (val != 5) { myList.push_front(val) // enqueue if not 5 } }
myList
现在只有数字1-4和6-10。
我认为你有一个错误,我这样编码:
for (std::list<CAudioChannel *>::iterator itAudioChannel = audioChannels.begin(); itAudioChannel != audioChannels.end(); ) { CAudioChannel *audioChannel = *itAudioChannel; std::list<CAudioChannel *>::iterator itCurrentAudioChannel = itAudioChannel; itAudioChannel++; if (audioChannel->destroyMe) { audioChannels.erase(itCurrentAudioChannel); delete audioChannel; continue; } audioChannel->Mix(outBuffer, numSamples); }