Подтвердить что ты не робот

Как вы перебираете назад через список STL?

Я пишу кросс-платформенный код между Windows и Mac.

Если list:: end() "возвращает итератор, который обращается к местоположению, следующему последнему элементу в списке" и может быть проверен при перемещении списка вперед, каков наилучший способ перемещения назад?

Этот код работает на Mac, но не в Windows (не может уменьшаться за пределами первого элемента):

list<DVFGfxObj*>::iterator iter = m_Objs.end();
for (iter--; iter!=m_Objs.end(); iter--)// By accident discovered that the iterator is circular ?
{
}

это работает в Windows:

list<DVFGfxObj*>::iterator iter = m_Objs.end();
    do{
        iter--;
    } while (*iter != *m_Objs.begin());

Есть ли другой способ перемещения назад, который может быть реализован в цикле for?

4b9b3361

Ответ 1

Используйте reverse_iterator вместо итератора. Используйте rbegin() и rend() вместо begin() и end().

Другая возможность, если вам нравится использовать макрос BOOST_FOREACH, заключается в использовании макроса BOOST_REVERSE_FOREACH, представленного в Boost 1.36.0.

Ответ 2

Лучший/самый простой способ перевернуть итерацию списка (как уже было сказано) для использования обратных итераторов rbegin/rend.

Однако я хотел бы упомянуть, что реализованы обратные итераторы, сохраняя "текущую" позицию итератора поочередно (по крайней мере, в реализации стандартной библиотеки GNU).

Это делается для упрощения реализации, чтобы диапазон в обратном направлении имел ту же семантику, что и диапазон вперед [начало, конец] и [rbegin, rend)

Это означает, что разыменование итератора предполагает создание нового временного и последующего его уменьшения каждый раз:

  reference
  operator*() const
  {
_Iterator __tmp = current;
return *--__tmp;
  }

Таким образом, разыменование обратного_тератора происходит медленнее, чем обычный итератор.

Однако вместо этого вы можете использовать обычные двунаправленные итераторы для имитации обратной итерации самостоятельно, избегая этих накладных расходов:

for ( iterator current = end() ; current != begin() ; /* Do nothing */ )
{
    --current; // Unfortunately, you now need this here
    /* Do work */
    cout << *current << endl;
}

Тестирование показало, что это решение было ~ 5 раз быстрее для каждого разыменования, используемого в теле цикла.

Примечание. Тестирование не было выполнено с помощью кода выше, так как std:: cout был бы узким местом.

Также обратите внимание: разность "настенных часов" составляла ~ 5 секунд с размером std:: list размером 10 миллионов элементов. Итак, реалистично, если размер ваших данных не такой большой, просто придерживайтесь rbegin() rend()!

Ответ 3

Вероятно, вам нужны обратные итераторы. Из памяти:

list<DVFGfxObj*>::reverse_iterator iter = m_Objs.rbegin();
for( ; iter != m_Objs.rend(); ++iter)
{
}

Ответ 4

Это должно работать:

list<DVFGfxObj*>::reverse_iterator iter = m_Objs.rbegin();
for (; iter!= m_Objs.rend(); iter++)
{
}

Ответ 5

Как уже упоминалось Ferruccio, используйте reverse_iterator:

for (std::list<int>::reverse_iterator i = s.rbegin(); i != s.rend(); ++i)