Как стереть *И ПРОДОЛЖИТЬ* с помощью std::reverse_iterator?

Я был вверх и вниз по stackoverflow, и даже очень, очень хороший Dr. Статья Доббса, но я не могу найти однозначного ответа на вопрос.

Раздел ответа на вопрос Каковы недостатки std::reverse_iterator? говорит, что это вообще невозможно.


std::list::reverse_iterator it = list.rbegin();

while(  it != list.rend() )
{
   int value=*it;
   if( some_cond_met_on(value) )
   {     
        ++it;
        list.erase( it.base() );
   }
   else
   {
     ++it;
   }
}

PS: я знаю, что есть и другие альтернативы, например, erase_if(), но я ищу ответ на этот конкретный вопрос.


person Migs    schedule 23.12.2011    source источник


Ответы (2)


Это должно быть просто

std::list<int>::reverse_iterator it = list.rbegin();

while(  it != list.rend() )
{
   int value=*it;
   if( some_cond_met_on(value) )
   {     
        ++it;
        it= reverse_iterator(list.erase(it.base()); // change to this!
   }
   else
   {
     ++it;
   }
}
person MSN    schedule 23.12.2011
comment
Я попробую. Как ты понял это? (Просто прошу научиться учиться) - person Migs; 24.12.2011
comment
@Migs, инвариант обратных итераторов: &*(reverse_iterator(i))==&*(i - 1). Сопоставьте это в обратном направлении (или просто подумайте об удалении rbegin()), и вы получите код в ответе. - person MSN; 24.12.2011
comment
Спасибо @MSN. Это сработало отлично. Я читал этот инвариант в статье Доббса, но, похоже, я просто не могу понять его значение. Я буду продолжать смотреть, пока что-то (надеюсь) не произойдет. - person Migs; 24.12.2011
comment
@Migs, мне тоже пришлось об этом подумать. Но если вы думаете об удалении rbegin() + 1 в [0, 1, 2, 3, 4], результат удаления правильного прямого итератора (через .erase()) будет именно там, где вы хотите, чтобы обратный итератор был построен поверх него. - person MSN; 24.12.2011
comment
@MichaelBurr, я показывал, что добавить в его фрагмент, но я отредактирую его, чтобы сделать его более очевидным. - person MSN; 24.12.2011
comment
Этот код не компилируется в Visual Studio. Разве ты не имеешь в виду it = std::list<int>::reverse_iterator(list.erase(it.base()));. Тоже вопрос, а не лучше ли в статике типа static_cast<std::list<int>::reverse_iterator>(list.erase(it.base()));. Спасибо - person loop; 10.03.2014

Большинство реализаций erase(), которые я видел, возвращают следующий итератор в последовательности именно для такой ситуации, например:

std::list<int>::reverse_iterator it = list.rbegin();
while( it != list.rend() )
{
    int value = *it;
    if( some_cond_met_on(value) )
    {
        it = list.erase( it );
    }
    else
    {
        ++it;
    }
}
person Remy Lebeau    schedule 24.12.2011
comment
Это верно. Однако стирание является членом структуры, а не итератора. Таким образом, независимо от того, используете ли вы итератор или reverse_iterator, функция erase() все равно принимает и возвращает итератор. Нет функции r_erase(), которая принимает и возвращает reverse_iterator. - person Dewi Morgan; 30.01.2015