![]() |
Здравствуйте, гость ( Вход | Регистрация )
![]() ![]() |
![]() |
AD |
![]()
Сообщение
#1
|
Профессионал ![]() ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 2003 Регистрация: 4.2.2008 Из: S-Petersburg Пользователь №: 84 Спасибо сказали: 70 раз(а) Репутация: ![]() ![]() ![]() |
Вот тестовый код:
Интересен он следующим. Если заменить первый элемент на неудаляемый (например push_back(1)), то программа нормально выполняется. Если же тестировать указанную версию, то варианты - разные. На моей машине с Ubuntu g++ 4.6.1 он падает. На машине другого форумчанина он тоже падает, как в MSVC, так и в g++ 4.7.1, а вот у третьего форумчанина с g++ 4.6.3 этот код не падает. Что же это? Сразу говорю, что берется старый стандарт, т.е. не 2011. Понятно, что невалидный итератор, но почему же тогда иногда работает? |
|
|
D_K |
![]()
Сообщение
#2
|
Студент ![]() Группа: Участник Сообщений: 20 Регистрация: 20.5.2009 Пользователь №: 761 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
Должно работать.
Работает не только у меня, но и у ideone.com: http://ideone.com/8kpis |
|
|
AD |
![]()
Сообщение
#3
|
Профессионал ![]() ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 2003 Регистрация: 4.2.2008 Из: S-Petersburg Пользователь №: 84 Спасибо сказали: 70 раз(а) Репутация: ![]() ![]() ![]() |
Должно работать. Должно, но не работает! ![]() Мда... Опишу вариант, в котором оно будет работать:
Разница в коде лишь в том, что итератор окончания вынесен за цикл:
|
|
|
D_K |
![]()
Сообщение
#4
|
Студент ![]() Группа: Участник Сообщений: 20 Регистрация: 20.5.2009 Пользователь №: 761 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
Ну вот.
Видимо дело в том, что при удалении первого элемента меняется мнимый элемент "перед первым", т.е. rend(). Допустим мы указываем reverse_iterator'ом на элемент перед rend(). Далее мы инкрементируем итератор(переходим на rend()). Вызываем base() - получаем итератор на первый элемент, удаляем его, после чего rend() в списке начинает ссылаться на что-то другое, чем ссылался ранее, но наш-то итератор продолжает указывать на предыдущий rend... Теперь надо выяснить, регламентирует ли это стандарт. |
|
|
Влад |
![]()
Сообщение
#5
|
Участник ![]() ![]() Группа: Участник Сообщений: 146 Регистрация: 20.3.2009 Из: Санкт-Петербург Пользователь №: 627 Спасибо сказали: 46 раз(а) Репутация: ![]() ![]() ![]() |
Код из сообщения #3 успешно отрабатывает в GCC 4.7.1 и валится в MSVC++ 2010 (конкретно, валится тут: for(list<int>::reverse_iterator i=my_list.rbegin(); i!=r_end; ) на вызове operator != ), - причем, валится после первой же итерации.....
Сообщение отредактировал Влад - 18.10.2012, 16:05 |
|
|
D_K |
![]()
Сообщение
#6
|
Студент ![]() Группа: Участник Сообщений: 20 Регистрация: 20.5.2009 Пользователь №: 761 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
На самом деле через reverse_iterator'ы нельзя удалять таким способом, т.к. по стандарту они работают с обычным итератором, который указывает на предыдущий(с точки зрения revers'а) элемент. А мы как раз его и удаляем. Соответственно reverse_iterator содержит ссылку на невалидный итератор.
|
|
|
Влад |
![]()
Сообщение
#7
|
Участник ![]() ![]() Группа: Участник Сообщений: 146 Регистрация: 20.3.2009 Из: Санкт-Петербург Пользователь №: 627 Спасибо сказали: 46 раз(а) Репутация: ![]() ![]() ![]() |
Гм. Не подкинешь ссылочку на соответствующий пункт? Потому что я пока не нашел.... :-(
У меня пока складывается впечатление, что это конкретная реализация содержит "просто итератор", который указывает на предыдущий (с точки зрения revers'а) элемент, и вот этот-то просто итератор - да, становится невалидным. Поэтому и падает. Интересно, что у Мейерса в Совете 28 приведен именно такой способ удаления элемента - с использованием (++ri).base(). |
|
|
D_K |
![]()
Сообщение
#8
|
Студент ![]() Группа: Участник Сообщений: 20 Регистрация: 20.5.2009 Пользователь №: 761 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
Я исхожу из описания std::reverse_iterator(24.4.1 в старом стандарте), т.к. в описании std::list явно указано typedef std::reverse_iterator<iterator> reverse_iterator
Интересно, что у Мейерса в Совете 28 приведен именно такой способ удаления элемента - с использованием (++ri).base(). Ну если ты потом не используешь ri, то все хорошо ![]() |
|
|
Iron Bug |
![]()
Сообщение
#9
|
![]() Профессионал ![]() ![]() ![]() ![]() ![]() Группа: Модератор Сообщений: 1611 Регистрация: 6.2.2009 Из: Yekaterinburg Пользователь №: 533 Спасибо сказали: 219 раз(а) Репутация: ![]() ![]() ![]() |
юзать i = my_list.erase(i) или my_list.erase(i++).
прочие варианты будут давать неверные указатели. |
|
|
D_K |
![]()
Сообщение
#10
|
Студент ![]() Группа: Участник Сообщений: 20 Регистрация: 20.5.2009 Пользователь №: 761 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
Ну почему же. Должно работать и так:
|
|
|
![]() ![]() ![]() |
![]() |
|
Текстовая версия | Сейчас: 18.2.2025, 17:24 |