Проблема с std:: map:: iterator после вызова erase()

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

не следует удалять "a => 10", но если я объявляю it = mymap.begin() в цикле for, все будет идеально. почему?

программа, адаптированная из: http://www.cplusplus.com/reference/stl/map/erase/

Ответы

Ответ 1

Стирание элемента map делает недействительными итераторы, указывающие на этот элемент (после того, как все эти элементы были удалены). Вы не должны повторно использовать этот итератор. Вместо этого переместите итератор на следующий элемент до удаления, например, например:

mymap.erase(it++);

Цикл, удаляющий некоторые элементы, может выглядеть так:

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

Ответ 2

Вызов erase() отменяет итератор. В этом случае, что происходит, итератор указывает на остаточное значение, оставшееся в памяти (но не полагайтесь на это поведение undefined!). Reset итератор с it=mymap.begin() перед циклом для желаемых результатов.

http://codepad.org/zVFRtoV5

Этот ответ показывает, как стирать элементы, итерации по 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;
    }
}

Ответ 3

Это связано с тем, как реализуется map. Скажем, это дерево какого-то типа, например:

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

Когда вы erase() итератор, вы удаляете node из дерева и освобождаете его пространство. Но пока это место памяти не будет перезаписано, содержимое node все еще находится в памяти.. Поэтому вы можете получить не только значение, но и следующий элемент в дереве. Таким образом, ваш результат полностью ожидается.

Ответ 4

it больше не действует после mymap.erase(it). Это означает, что он может делать все, что захочет.

Ответ 5

"он" все еще указывает на одно и то же место, стирание не обновляет итератор сам по себе, вы должны сделать это, сбросив итератор. По сути, "это" указывает на старое местоположение, которое было стерто из вектора, но все еще содержит старые данные.