C++ 如何使用迭代器删除 std::map 的元素?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4600567/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 15:53:29  来源:igfitidea点击:

How can I delete elements of a std::map with an iterator?

c++mapiteratorstdmap

提问by templatetypedef

I would like to loop through an std::mapand delete items based on their contents. How best would this be done?

我想遍历一个std::map并根据其内容删除项目。如何最好地做到这一点?

回答by templatetypedef

If you have a C++11-compliant compiler, here's an easy way to do this:

如果你有一个 C++11 兼容的编译器,这里有一个简单的方法来做到这一点:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       itr = myMap.erase(itr);
    } else {
       ++itr;
    }
}

The idea is to walk the iterator forward from the start of the container to the end, checking at each step whether the current key/value pair should be deleted. If so, we remove the element iterated over using the erasemember function, which then returns an iterator to the next element in the map. Otherwise, we advance the iterator forward normally.

这个想法是让迭代器从容器的开始到结束向前走,在每一步检查是否应该删除当前的键/值对。如果是这样,我们使用erase成员函数删除迭代的元素,然后返回一个迭代器到映射中的下一个元素。否则,我们将正常推进迭代器。

If you do not have a C++11-compliant compiler, or you're working with an older codebase, things are a bit trickier. Before C++11, the erasemember function would not return an iterator to the next element in the map. This meant that in order to remove an element while iterating, you'd need to use a three-part dance:

如果您没有符合 C++11 的编译器,或者您使用的是较旧的代码库,事情就会有点棘手。在 C++11 之前,erase成员函数不会返回到映射中下一个元素的迭代器。这意味着为了在迭代时删除元素,您需要使用三部分舞蹈:

  1. Copy the current iterator.
  2. Advance the current iterator to the next element.
  3. Call eraseon the copy of the old iterator.
  1. 复制当前迭代器。
  2. 将当前迭代器推进到下一个元素。
  3. 调用erase旧迭代器的副本。

This is shown here:

这在这里显示:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       std::map<K, V>::iterator toErase = itr;
       ++itr;
       myMap.erase(toErase);
    } else {
       ++itr;
    }
}

This process was required because if you just called eraseon the iterator, you'd invalidateit, meaning that operations like increment and decrement would lead to undefined behavior. The above code gets around this by setting up a copy of the iterator, advancing itrso that it's at the next element, then erasing the temporary copy of the iterator.

这个过程是必需的,因为如果你只是调用erase迭代器,你会使其无效,这意味着像增量和减量这样的操作会导致未定义的行为。上面的代码通过设置迭代器的副本,前进itr到下一个元素,然后擦除迭代器的临时副本来解决这个问题。

Using some Clever Trickiness, it's possible to shrink this code down at the expense of readability. The following pattern is common in older C++ code, but isn't necessary in C++11:

使用一些巧妙的技巧,可以以牺牲可读性为代价来缩小此代码。以下模式在较旧的 C++ 代码中很常见,但在 C++11 中不是必需的:

std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
    if (ShouldDelete(*itr)) {
       myMap.erase(itr++);  // <--- Note the post-increment!
    } else {
       ++itr;
    }
}

The use of the post-increment operator here is a clever way of making a copy of the old iterator (remember that a postfix ++ operator returns a copy of the original iterator value) while also advancing the older iterator.

此处使用后增量运算符是一种制作旧迭代器副本的巧妙方法(请记住,后缀 ++ 运算符返回原始迭代器值的副本),同时还推进旧迭代器。

回答by Timo

for(MyMap::iterator it = mymap.begin(); it!=mymap.end(); ) {
  if(mycondition(it))
    it = mymap.erase(it);
  else
    it++;
}

edit: seems that this works in MSVC only

编辑:似乎这仅适用于 MSVC

edit2: in c++0x this works for associative containers too

编辑 2:在 c++0x 中,这也适用于关联容器

回答by Chan


This is one simple way:


这是一种简单的方法:

    int value_to_delete( 2 );
    for( std::map<int, int>::iterator i = mm.begin(); i != mm.end(); ) {
        if( i->second != value_to_delete ) {
            mm.erase( i++ ); // advance before iterator become invalid
        }
        else {
            ++i;
        }
    }