Я пытаюсь сделать что-то вроде этого:
for ( std::list< Cursor::Enum >::reverse_iterator i = m_CursorStack.rbegin(); i != m_CursorStack.rend(); ++i )
{
if ( *i == pCursor )
{
m_CursorStack.erase( i );
break;
}
}
Однако стирание требует итератор, а не обратный итератор. Есть ли способ преобразовать обратный итератор в обычный итератор или другой способ удалить этот элемент из списка?
i != m_CursorStack.rend()
. Вместо этого пишиi = m_CursorStack.rbegin(), end = m_CursorStack.rend(); i != end;
. То есть инициализируйте итератор, который вы можете использовать для повторного сравнения - при условии, что конечная позиция не изменится как побочный эффект вашего тела цикла.std::remove
?Ответы:
После еще нескольких исследований и испытаний я нашел решение. По-видимому, согласно стандарту [24.4.1 / 1] связь между i.base () и i:
(из статьи доктора Доббса ):
Поэтому вам нужно применить смещение при получении base (). Поэтому решение:
РЕДАКТИРОВАТЬ
Обновление для C ++ 11.
reverse_iterator
i
не изменяется:обратный_тератор
i
расширен:Я нахожу это намного яснее, чем мое предыдущее решение. Используйте то, что вам нужно.
источник
m_CursorStack.erase( (++i).base())
(чувак, от этой работы с обратными итераторами у меня болит голова ...). Следует также отметить, что статья DDJ включена в книгу Мейера «Effective STL».*
их использовали, но мы говорим о том, на какой элемент вы бы указывали, если бы выbase
их использовали, то есть один элемент справа. Я не такой фанат--(i.base())
или(++i).base()
решений, поскольку они мутируют итератор. Я предпочитаю(i+1).base()
что работает, а также.Обратите внимание, что это
m_CursorStack.erase( (++i).base())
может быть проблемой, если используется вfor
цикле (см. Оригинальный вопрос), потому что это меняет значение i. Правильное выражениеm_CursorStack.erase((i+1).base())
источник
iterator j = i ; ++j
, потому чтоi+1
он не работает на итераторе, но это правильная идеяm_CursorStack.erase(boost::next(i).base())
с Boost. или в C ++ 11m_CursorStack.erase(std::next(i).base())
Для этого требуется
-std=c++11
флаг (дляauto
):источник
Забавно, что на этой странице пока нет правильного решения. Итак, следующее является правильным:
В случае прямого итератора решение является прямым:
В случае обратного итератора вам нужно сделать то же самое:
Ноты:
reverse_iterator
из итератораstd::list::erase
источник
Несмотря на то, что здесь используется метод
reverse_iterator
'' '' '' '' '' '' '' '' '']]base()
и уменьшающий результат, стоит отметить, чтоreverse_iterator
s не имеют такой же статус, как обычныеiterator
s. В общем, вы должны предпочесть обычныеiterator
sreverse_iterator
s (а такжеconst_iterator
s иconst_reverse_iterator
s), именно по таким причинам. Посмотрите Журнал Доктора Доббса для всестороннего обсуждения почему.источник
источник
А вот фрагмент кода для преобразования результата стирания обратно в обратный итератор, чтобы стереть элемент в контейнере при итерации в обратном порядке. Немного странно, но это работает даже при удалении первого или последнего элемента:
источник
Если вам не нужно стирать все по ходу дела, то для решения проблемы вы можете использовать идиому удаления-удаления:
std::remove
Меняет местами все элементы в контейнере, которые соответствуютpCursor
концу, и возвращает итератор к первому элементу соответствия. Затемerase
использование диапазона сотрет с первого совпадения и пойдет до конца. Порядок несовпадающих элементов сохраняется.Это может сработать быстрее для вас, если вы используете
std::vector
, где удаление в середине содержимого может потребовать большого количества копирования или перемещения.Или, конечно, ответы выше, объясняющие использование
reverse_iterator::base()
, интересны и их стоит знать, чтобы решить поставленную задачу, я бы сказал, чтоstd::remove
она лучше подходит.источник
Просто хотел кое-что прояснить: в некоторых из приведенных выше комментариев и ответов портативная версия для стирания упоминается как (++ i) .base (). Однако, если я что-то упускаю, правильное утверждение (++ ri) .base () означает, что вы «увеличиваете» обратный итератор (а не итератор).
Я столкнулся с необходимостью сделать что-то подобное вчера, и этот пост был полезен. Спасибо всем.
источник
Чтобы дополнить ответы других и потому что я наткнулся на этот вопрос во время поиска std :: string без особого успеха, здесь идет ответ с использованием std :: string, std :: string :: erase и std :: reverse_iterator
Моя проблема заключалась в удалении файла изображения из полной строки имени файла. Первоначально она была решена с помощью std :: string :: find_last_of, но я исследую альтернативный способ с помощью std :: reverse_iterator.
Это использует алгоритм, итератор и заголовки строк.
источник
Обратный итератор довольно сложен в использовании. Так что просто использовал общий итератор. 'r' Это начинается с последнего элемента. Когда найдешь что стереть. сотри его и верни следующий итератор. например, при удалении 3-го элемента он будет указывать текущий 4-й элемент. и новый 3-й. Таким образом, это должно быть уменьшено на 1, чтобы двигаться влево
источник