Странное поведение при стирании элемента из std::multimap

Я пытался удалить элемент из std::multimap, когда я зацикливался на нем в потоке, который им манипулирует. Я использовал функцию стирания следующими способами.

Когда я делаю это

//mItr is base iterator which loops over the multimap

std::multimap<std::string, std::string>::iterator tmpItr = ++mItr;
healthyQ.erase(mItr);
mItr = tmpItr;

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

mItr = healthyQ.erase(mItr);

Это сработало. На это ушло много времени, и я до сих пор не уверен, в чем может быть проблема.


person cbinder    schedule 18.05.2015    source источник
comment
Как именно вы получаете проверенный итератор? У вас есть итератор для стертого элемента.   -  person juanchopanza    schedule 18.05.2015
comment
@juanchopanza После выполнения как первый, так и второй сценарии должны сделать mItr итератором, указывающим на следующий элемент.   -  person cbinder    schedule 18.05.2015
comment
У вас нет допустимого итератора после функции стирания. Вместо этого у вас есть недопустимый итератор, который был допустимой позицией до вызова стирания. Второй способ (mItr = healthyQ.erase(mItr);) является правильным способом выполнения операции (присваивание заменяет приращение ++, которое вы обычно делаете).   -  person utnapistim    schedule 18.05.2015
comment
Обратите внимание, что tmpItr равно mItr еще до присваивания из-за предварительного приращения, т. е. tmpItr также относится к элементу, который вы только что стерли.   -  person molbdnilo    schedule 18.05.2015


Ответы (2)


Второй способ именно так и должен работать.

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

Вы можете увидеть здесь, как работает удаление в красно-черном дереве .

person Ami Tavory    schedule 18.05.2015
comment
В нескольких местах на sf предлагается первое решение для получения следующего проверенного итератора. - person cbinder; 18.05.2015
comment
Вы правильно упомянули, что второй случай - лучший способ стереть. - person cbinder; 18.05.2015
comment
@cbinder: В нескольких местах на научной фантастике — что такое научная фантастика? Вы имели в виду это (переполнение стека)? Если да, то покажите где - попробуем исправить. Ваше здоровье. - person Tony Delroy; 18.05.2015

Вы сделали итератор недействительным, вызвав функцию erase(). Поэтому, когда вы фиксируете возврат итератора из erase() и повторно используете позже, вы правильно обрабатываете итератор и избегаете его недействительности.

person Steephen    schedule 18.05.2015