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

时间:2011-01-08 21:14:39

标签: c++ iterator

// 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;
}

为什么这会产生类似

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

不应该{@ 1}}被删除,但如果我在for循环中声明"a => 10",一切都很完美。为什么呢?

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

5 个答案:

答案 0 :(得分:39)

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

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

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

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

mymap.erase(it++);

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

答案 1 :(得分:3)

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

http://codepad.org/zVFRtoV5

This answer显示了在迭代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;
    }
}

答案 2 :(得分:1)

这与map的实施方式有关。让我们说它是某种树,比如:

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

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

答案 3 :(得分:0)

it之后

mymap.erase(it)不再有效。这意味着,它可以做任何想做的事。

答案 4 :(得分:0)

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