您可以在迭代 std::list 时从其中删除元素吗?
我的代码如下所示:
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::list 时,删除项目的最佳方法是什么?
I've got code that looks like this:
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'd like remove inactive items immediately after update them, in order to avoid walking the list again. But if I add the commented-out lines, I get an error when I get to i++
: "List iterator not incrementable". I tried some alternates which didn't increment in the for statement, but I couldn't get anything to work.
What's the best way to remove items as you are walking a std::list?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
您必须首先递增迭代器(使用 i++),然后删除前一个元素(例如,通过使用 i++ 的返回值)。 您可以将代码更改为 while 循环,如下所示:
You have to increment the iterator first (with i++) and then remove the previous element (e.g., by using the returned value from i++). You can change the code to a while loop like so:
您想要执行的操作:
这将正确更新迭代器以指向您删除的迭代器之后的位置。
You want to do:
That will correctly update the iterator to point to the location after the iterator you removed.
您需要将 Kristo 的答案和 MSN 的答案结合起来:
当然,最有效和 SuperCool® STL 精明的事情将是这样的:
You need to do the combination of Kristo's answer and MSN's:
Of course, the most efficient and SuperCool® STL savy thing would be something like this:
我总结了一下,这里是三个方法的例子:
1. 使用
while
循环2. 使用
remove_if
list: 中的成员函数3. 使用
std:: remove_if
函数与erase
成员函数结合使用:4. 使用
for
循环,需要注意更新迭代器:I have sumup it, here is the three method with example:
1. using
while
loop2. using
remove_if
member funtion in list:3. using
std::remove_if
funtion combining witherase
member function:4. using
for
loop , should note update the iterator:使用 std::remove_if 算法。
编辑:
使用集合应该像:
如果您不混淆这些步骤,生活会更容易。
std::remove_if
。 或list::remove_if
(如果您知道您使用列表而不是TCollection
)std::for_each
Use
std::remove_if
algorithm.Edit:
Work with collections should be like:
Life will be easier if you won't mix this steps.
std::remove_if
. orlist::remove_if
( if you know that you work with list and not with theTCollection
)std::for_each
Kristo 答案的替代 for 循环版本。
您会损失一些效率,删除时会向后然后再次向前,但作为额外的迭代器增量的交换,您可以在循环范围中声明迭代器,并且代码看起来更干净一些。 选择什么取决于当前的优先事项。
我知道答案完全不合时宜......
The alternative for loop version to Kristo's answer.
You lose some efficiency, you go backwards and then forward again when deleting but in exchange for the extra iterator increment you can have the iterator declared in the loop scope and the code looking a bit cleaner. What to choose depends on priorities of the moment.
The answer was totally out of time, I know...
下面是一个使用
for
循环的示例,该循环迭代列表并在遍历列表期间删除项目时递增或重新验证迭代器。Here's an example using a
for
loop that iterates the list and increments or revalidates the iterator in the event of an item being removed during traversal of the list.对于 C++20,您可以使用
std::erase_if
:
With C++20, you can use
std::erase_if
:删除只会使指向被删除元素的迭代器无效。
因此,在这种情况下,删除 *i 后, i 无效,您无法对其进行增量。
您可以做的是,首先保存要删除的元素的迭代器,然后递增迭代器,然后删除保存的迭代器。
Removal invalidates only the iterators that point to the elements that are removed.
So in this case after removing *i , i is invalidated and you cannot do increment on it.
What you can do is first save the iterator of element that is to be removed , then increment the iterator and then remove the saved one.
向后迭代可以避免擦除某个元素对要遍历的剩余元素的影响:
PS:请参见这个,例如,关于向后迭代迭代。
PS2:我没有彻底测试它是否能够很好地擦除末端的元素。
Iterating backwards avoids the effect of erasing an element on the remaining elements to be traversed:
PS: see this, e.g., regarding backward iteration.
PS2: I did not thoroughly tested if it handles well erasing elements at the ends.
如果您将 std::list 视为队列,那么您可以将要保留的所有项目出队和入队,但只能将要删除的项目出队(而不是入队)。 下面是一个示例,我想从包含数字 1-10 的列表中删除 5...
myList
现在只有数字 1-4 和 6-10。If you think of the
std::list
like a queue, then you can dequeue and enqueue all the items that you want to keep, but only dequeue (and not enqueue) the item you want to remove. Here's an example where I want to remove 5 from a list containing the numbers 1-10...myList
will now only have numbers 1-4 and 6-10.您可以
使用
std::list::remove_if
编写等效代码,该代码更简洁、更明确std::vector::erase
std当 items 是一个向量而不是一个列表时,应该使用 ::remove_if
习惯用法,以将复杂性保持在 O(n) - 或者如果您编写通用代码并且 items 可能是一个容器,没有有效的方法来删除单个项目(像向量一样)You can write
You can write equivalent code with
std::list::remove_if
, which is less verbose and more explicitThe
std::vector::erase
std::remove_if
idiom should be used when items is a vector instead of a list to keep compexity at O(n) - or in case you write generic code and items might be a container with no effective way to erase single items (like a vector)do while 循环,灵活、快速且易于读写。
do while loop, it's flexable and fast and easy to read and write.
我想分享一下我的方法。 该方法还允许在迭代期间将元素插入到列表的后面
I'd like to share my method. This method also allows the insertion of the element to the back of the list during iteration
我认为你那里有一个错误,我这样编码:
I think you have a bug there, I code this way: