Как вызвать стирание с помощью обратного итератора
Я пытаюсь сделать что-то вроде этого:
for ( std::list< Cursor::Enum >::reverse_iterator i = m_CursorStack.rbegin(); i != m_CursorStack.rend(); ++i )
{
if ( *i == pCursor )
{
m_CursorStack.erase( i );
break;
}
}
Однако erase принимает итератор, а не обратный итератор. есть ли способ конвертировать обратный итератор в обычный итератор или другой способ удалить этот элемент из списка?
Ответы
Ответ 1
После нескольких исследований и испытаний я нашел решение. По-видимому, согласно стандарту [24.4.1/1], отношение между i.base() и я равно:
&*(reverse_iterator(i)) == &*(i - 1)
(из статья доктора Доббса):
![alt text]()
Поэтому вам нужно применить смещение при получении базы(). Поэтому решение:
m_CursorStack.erase( --(i.base()) );
ИЗМЕНИТЬ
Обновление для С++ 11.
reverse_iterator i
не изменяется:
m_CursorStack.erase( std::next(i).base() );
reverse_iterator i
:
std::advance(i, 1);
m_CursorStack.erase( i.base() );
Я нахожу это намного более ясным, чем мое предыдущее решение. Используйте то, что вам нужно.
Ответ 2
Обратите внимание, что m_CursorStack.erase( (++i).base())
может быть проблемой, если используется в цикле for
(см. исходный вопрос), потому что он меняет значение i. Правильное выражение m_CursorStack.erase((i+1).base())
Ответ 3
... или другой способ удалить этот элемент из списка?
Для этого требуется флаг -std=c++11
(для auto
):
auto it=vt.end();
while (it>vt.begin())
{
it--;
if (*it == pCursor) //{ delete *it;
it = vt.erase(it); //}
}
Ответ 4
При использовании метода reverse_iterator
base()
и уменьшения результата результат здесь стоит отметить, что reverse_iterator
не получает тот же статус, что и обычный iterator
s. В общем, вы должны предпочесть регулярный iterator
до reverse_iterator
(а также const_iterator
и const_reverse_iterator
s), в силу таких причин. См. Journal Dobbs 'Journal для углубленного обсуждения причин.
Ответ 5
typedef std::map<size_t, some_class*> TMap;
TMap Map;
.......
for( TMap::const_reverse_iterator It = Map.rbegin(), end = Map.rend(); It != end; It++ )
{
TMap::const_iterator Obsolete = It.base(); // conversion into const_iterator
It++;
Map.erase( Obsolete );
It--;
}
Ответ 6
Если вам не нужно стирать все по ходу дела, то для решения проблемы вы можете использовать стирание-удалить идиому:
m_CursorStack.erase(std::remove(m_CursorStack.begin(), m_CursorStack.end(), pCursor), m_CursorStack.end());
std::remove
заменяет все элементы в контейнере, которые соответствуют pCursor
до конца, и возвращает итератор в первый элемент соответствия. Затем erase
, используя диапазон, будет удаляться из первого совпадения и идти до конца. Порядок несогласованных элементов сохраняется.
Это может работать быстрее для вас, если вы используете std::vector
, где удаление в середине содержимого может привести к большому количеству копий или перемещений.
Или курс, ответы выше, объясняющие использование reverse_iterator::base()
, интересны и заслуживают внимания, чтобы решить указанную точную проблему, я бы сказал, что std::remove
лучше подходит.
Ответ 7
Просто хотел прояснить что-то: В некоторых из приведенных выше комментариев и ответов портативная версия для удаления упоминается как (++ i).base(). Однако, если мне не хватает чего-то правильного утверждения (++ ri).base(), что означает, что вы "увеличиваете" обратный_тератор (не итератор).
Я столкнулся с необходимостью сделать что-то подобное вчера, и этот пост был полезен. Спасибо всем.