Обратный итератор продвигается с помощью std::set::erase

Я пытаюсь стереть элемент, в который я только что прошел. Сначала я забыл сохранить возвращаемое значение s1.erase (... внутри цикла for, чтобы в конечном итоге установить условие выхода из цикла. Учитывая то, как работает код, я ожидал, что цикл будет продолжаться бесконечно. Но он работает просто так, как он изначально был предназначен для работы. Похоже, что std::erase продвигает итератор и сохраняет значение в rit. Я не могу найти документацию, которая объясняет это поведение.

https://en.cppreference.com/w/cpp/container/set/erase говорит, что возвращаемый итератор должен быть сохранен. Все аргументы set::erase передаются по значению, так как продвигается обратный итератор?

Как завершается этот цикл?

std::set<int> s1;
s1.insert(20);
s1.insert(30);
s1.insert(50);

auto rit = s1.rbegin();

for (; rit!= s1.rend();)
{
    std::cout << "rit is " << *rit << " size is " << s1.size() << std::endl;
    s1.erase(std::next(rit).base());
    std::cout << "rit after erase is " << *rit << std::endl;
}

Выход

ритм 50 размер 3

Рит после стирания 30

ритм 30 размер 2

Рит после стирания 20

ритм 20 размер 1

Ошибка сегментации

1 ответ

Решение

Напомним, что reverse_iterator::base() всегда один элемент за очевидным значением итератора. Например, после auto rit = s1.rbegin(), *rit возвращает последний элемент, в то время как rit.base() == s1.end(),

Другими словами, *rit == *prev(rit.base())

В вашем цикле, изначально rit.base() == s1.end(), затем std::next(rit).base() относится к последнему элементу; этот элемент стирается. В std::setСтирание элемента делает недействительными только итераторы для этого элемента, но не для других. s1.end() все еще действительный итератор, и поэтому rit, с rit.base() все еще равно s1.end(), Итак, на следующей итерации цикла вы снова стираете последний элемент и оставляете rit.base() == s1.end() снова. И так далее.

В какой-то момент последний элемент стирается, s1 становится пустым, а затем *rit проявляет неопределенное поведение. Напомним, что *rit == *prev(rit.base()), но предыдущего элемента больше нет.

Другие вопросы по тегам