несовместимое поведение с удалением итераторов карты в C ++

0

Я очень смущен поведением функции стирания для карт. В простом примере ниже код выводит "224". Однако, если вы закомментируете строку "m ['e'] = 5", она выведет "221". Ни один результат не имеет смысла для меня. Может ли кто-нибудь объяснить здесь логику?

#include <iostream>
#include <map>
using namespace std;

int main(){

        map<char, int> m;
        m['a'] = 1;
        m['b'] = 2;
        m['c'] = 3;
        m['d'] = 4;
        m['e'] = 5;

        map<char, int>::iterator it = m.begin();        it++; 
        cout << it->second;                             
        m.erase(it); 
        cout << it->second;
        it++;
        cout << it->second << endl;
}
Теги:
iterator
erase
map

3 ответа

3

Вы не можете использовать итератор после его стирания. Это недопустимо, и поведение не определено (crash, wriong value?):

http://en.cppreference.com/w/cpp/container/map/erase

  • 0
    Хорошо, это объясняет это. Однако нельзя ли использовать векторные итераторы после удаления?
  • 0
    Более того, цитирование cppreference : итераторы и ссылки на стертые элементы и элементы между ними и концом контейнера становятся недействительными. Последний итератор также становится недействительным.
Показать ещё 12 комментариев
0

Чтобы стереть элементы на карте для pre C++ 11, вы можете использовать этот шаблон:

for( map_type::iterator it = map.begin(); it != map.end(); ) {
   if( condition_to_erease ) map.erase( it++ );
   else ++i;
}

Почему map.erase( it++ ); работает? Поскольку это в основном эквивалентно этому коду:

map::iterator tmp = it;
++it;
map.erase( tmp );

Вы должны понимать семантику операторов postfics/prefics, если вы хотите эффективно использовать C++.

Для C++ 11 вы также можете использовать это:

for( auto it = map.begin(); it != map.end(); ) {
   if( condition_to_erease ) it = map.erase( it );
   else ++i;
}

Я думаю, что в Visual C++ std::map::erase() erase std::map::erase() также возвращался итератор, но это не было стандартным.

0
map<char, int>::iterator it = m.begin();        it++; 
cout << it->second;                             
m.erase(it);  // (1) 
cout << it->second; // (2)
it++; // (3)
cout << it->second << endl;

Вы аннулировали итератор в позиции (1), поэтому попытка разыменовать его в (2) и (3) является неопределенным поведением. Он практически идентичен удалению указателя, а затем пытается разыменовать его.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню