如何在STL set中迭代并有选择地删除元素?

7
以下代码不正确,请问应该如何正确实现?
for (std::set<Color>::iterator i = myColorContainer.begin();
            i!=myColorContainer.end();
            ++i)
{
    if ( *i  == Yellow)
    {
        DoSomeProccessing( *i );
        myColorContainer.erase(i);
    }
}
3个回答

7

尝试:

for(std::set<Color>::iterator it = myColorContainer.begin(); 
    it != myColorContainer.end();) { // note missing it++
     if( (*it) == Yellow ) {
        DoSomeProcessing(*it);
        myColorContainer.erase(it++); // post increment (original sent to erase)
     }
     else {
       ++it; // more efficient than it++;
     }
}

这样也不行。你应该再次将erase的返回值赋给它。 - Patrick
返回的迭代器是微软特定的实现,违反了标准:http://msdn.microsoft.com/en-us/library/8h4a3515%28VS.80%29.aspx。确实,在擦除之后需要递增迭代器。 - Adrian Regan
1
如果您无法使用微软特定的实现并且需要使用循环,则此解决方案非常完美。如果您不需要使用循环,Viktor的选项甚至更好。感谢您提供出色的答案。您一直是一个巨大的帮助。 - scippie

6

你不需要使用循环,因为你正在处理一个集合。

std::set<Color>::iterator it = myColorContainer.find(Yellow);
if (it != it.myColorContainer.end()){
  DoSomeProcessing(*it);
  myColorContainer.erase(it);
}

1
代码符合标准。我同意 @Viktor Sehr 的看法,这是从集合中移除元素的首选方法。然而,问题要求如何让代码片段运行。 - Adrian Regan
我认为你是在我编辑代码后回答的(我第一篇帖子中认为它是std :: vector)。 - Viktor Sehr

2
for (std::set<Color>::iterator i = myColorContainer.begin();
            i!=myColorContainer.end(); /* No i++ */)
{
    if ( *i  == Yellow)
    {
        DoSomeProccessing( *i );
        std::set<Color>::iterator tmp = i;
        ++i;
        myColorContainer.erase(tmp);
    }
    else {
        ++i;
    }
}

当使用++i转到下一条消息时,可以保证它是有效的 - 这是std::set的一个属性,即插入元素的迭代器不会失效,除非该元素被删除。

因此,现在您可以安全地删除先前的条目。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接