Я очень смущен поведением функции стирания для карт. В простом примере ниже код выводит "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;
}
Вы не можете использовать итератор после его стирания. Это недопустимо, и поведение не определено (crash, wriong value?):
Чтобы стереть элементы на карте для 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()
также возвращался итератор, но это не было стандартным.
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)
является неопределенным поведением. Он практически идентичен удалению указателя, а затем пытается разыменовать его.