причина проблемы
Когда вы вызываете m.erase(0)
в вашем примере, it
указывает на элемент с ключом 0
, поэтому it
становится недействительным. m.erase(1)
работает, потому что при первом вызове it
не указывает на элемент с ключом 1
, поэтому на него это не влияет. В последующих итерациях элементы с ключом 1
не остаются, поэтому ничего не удаляется и итератор не затрагивается.
Решение
multimap
не имеет erase
-метода, который возвращает следующий действительный итератор. Один из вариантов - позвонить it = m.upper_bound(deleted_key);
после удаления. Однако это логарифмическая операция, которая может быть слишком медленной для вашего сценария (erase(x)
и upper_bound
- две логарифмические операции).
Предполагая, что вы хотите стереть ключ, на который в данный момент указывает итератор, вы можете сделать что-то вроде этого (в противном случае erase
, конечно, хорошо; не проверено):
std::multimap<int, int>::iterator interval_start = m.begin();
for(std::multimap<int, int>::iterator it=m.begin(); it!=m.end(); ++it) {
if(interval_start->first < it->first) // new interval starts here
interval_start == it;
if( (*it).second == 3 ) {
std::multimap<int, int>::iterator interval_end = it;
while((interval_end != m.end()) && (interval_end->first == it->first)) {
++interval_end; // search for end of interval - O(n)
}
m.erase(interval_start, interval_end); // erase interval - amortized O(1)
it = interval_end; // set it to first iterator that was not erased
interval_start = interval_end; // remember start of new interval
}
}
При этом используется одна линейная операция, все остальные имеют постоянное время. Если ваша карта очень большая, и у вас есть только несколько предметов с одинаковыми ключами, это, вероятно, будет быстрее. Однако, если у вас много элементов с одинаковыми ключами, поиск конца интервала, вероятно, лучше выполнить с помощью upper_bound
(O(log n)
вместо O(n)
при поиске конца интервала).