Как вызвать стирание с помощью обратного итератора

Я пытаюсь сделать что-то вроде этого:

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(), что означает, что вы "увеличиваете" обратный_тератор (не итератор).

Я столкнулся с необходимостью сделать что-то подобное вчера, и этот пост был полезен. Спасибо всем.