C++ 调用 erase() 后 std::map::iterator 出现问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4636182/
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 16:00:39  来源:igfitidea点击:

Problem with std::map::iterator after calling erase()

c++iterator

提问by 0x0

// erasing from map
#include <iostream>
#include <map>
using namespace std;

int main ()
{
  map<char,int> mymap;
  map<char,int>::iterator it(mymap.begin());

  // insert some values:
  mymap['a']=10;
  mymap['b']=20;
  mymap['c']=30;
  mymap['d']=40;
  mymap['e']=50;
  mymap['f']=60;

  it=mymap.find('a');
  mymap.erase (it);                   // erasing by iterator

  // show content:
  for (; it != mymap.end(); it++ )
    cout << (*it).first << " => " << (*it).second << endl;
  return 0;
}

Why does this give an output like

为什么这会给出类似的输出

a => 10
b => 20
c => 30
d => 40
e => 50
f => 60

shouldn't "a => 10"be deleted anyways, but if I declare it = mymap.begin()in the for loop, everything is perfect. why?

"a => 10"无论如何都不应该被删除,但是如果我it = mymap.begin()在 for 循环中声明,一切都是完美的。为什么?

program adapted from : http://www.cplusplus.com/reference/stl/map/erase/

程序改编自:http: //www.cplusplus.com/reference/stl/map/erase/

回答by sth

Erasing an element of a mapinvalidates iterators pointing to that element (after all that element has been deleted). You shouldn't reuse that iterator.

擦除 a 的元素map会使指向该元素的迭代器失效(在所有该元素已被删除之后)。你不应该重用那个迭代器。

Since C++11 erase()returns a new iterator pointing to the next element, which can be used to continue iterating:

由于 C++11erase()返回一个指向下一个元素的新迭代器,可用于继续迭代:

it = mymap.begin();
while (it != mymap.end()) {
   if (something)
      it = mymap.erase(it);
   else
      it++;
}

Before C++11 you would have to manually advance the iterator to the next element before the deletion takes place, for example like this:

在 C++11 之前,您必须在删除之前手动将迭代器推进到下一个元素,例如:

mymap.erase(it++);

This works because the post-increment side-effect of it++happens before erase()deletes the element. Since this is maybe not immediately obvious, the C++11 variant above should be preferred.

这是有效的,因为 的后增量副作用it++发生在erase()删除元素之前。由于这可能不是很明显,因此上面的 C++11 变体应该是首选。

回答by moinudin

Calling erase()invalidates the iterator. In this case, what's happening is the iterator points to the residual value left behind in memory (but don't rely on this undefined behaviour!). Reset the iterator with it=mymap.begin()before the loop for the desired results.

调用erase()会使迭代器失效。在这种情况下,发生的事情是迭代器指向留在内存中的剩余值(但不要依赖这种未定义的行为!)。it=mymap.begin()在循环之前重置迭代器以获得所需的结果。

http://codepad.org/zVFRtoV5

http://codepad.org/zVFRtoV5

This answershows how to erase elements while iterating over an std::map:

这个答案显示了如何在迭代时擦除元素std::map

for(map<T, S*>::iterator it = T2pS.begin(); it != T2pS.end(); T2pS.erase(it++)) {
    // wilhelmtell in the comments is right: no need to check for NULL. 
    // delete of a NULL pointer is a no-op.
    if(it->second != NULL) {
        delete it->second;
            it->second = NULL;
    }
}

回答by chrisaycock

This has to do with how the mapis implemented. Let's say it's a tree of some sort, like:

这与map实现的方式有关。假设它是某种树,例如:

class map_node {
    char key;
    int  value;
    map_node* next;
    ...
};

When you erase()the iterator, you remove the node from the tree and deallocate its space. But until that memory location is overwritten, the node's contents are still in memory.That's why you can get not only the value, but also the next element in the tree. Thus, your result is completely expected.

当您erase()使用迭代器时,您从树中删除节点并释放其空间。但是在该内存位置被覆盖之前,节点的内容仍在内存中。这就是为什么您不仅可以获得值,还可以获得树中的下一个元素。因此,您的结果完全符合预期。

回答by Oswald

itis no longer valid after mymap.erase(it). This means, it can do whatever it wants.

it之后不再有效mymap.erase(it)。这意味着,它可以为所欲为。

回答by Akhil

"it" still points at the same location, erase does not update the iterator by itself, you have to do it, by resetting the iterator. In effect, "it" points to the old location which has been erased from the vector but still contains the old data.

“它”仍然指向同一个位置,擦除不会自己更新迭代器,你必须通过重置迭代器来做到这一点。实际上,“它”指向已从向量中删除但仍包含旧数据的旧位置。