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

Итерация над вектором в обратном направлении

Мне нужно перебрать вектор с конца на начальный. "Правильный" способ -

for(std::vector<SomeT>::reverse_iterator rit = v.rbegin(); rit != v.rend(); ++rit)
{
    //do Something
}

Когда doSomething включает в себя знание фактического индекса, тогда некоторые вычисления должны выполняться с помощью rit для его получения, например index = v.size() - 1 - (rit - v.rbegin)

Если индекс нужен в любом случае, то я твердо верю, что лучше итерации с использованием этого индекса

for(int i = v.size() - 1; i >= 0; --i)
{
    //do something with v[i] and i; 
}

Это дает предупреждение о том, что i подписан, а v.size() - без знака. Переход на

for(unsigned i = v.size() - 1; i >= 0; --i) является просто функционально неправильным, потому что это по существу бесконечный цикл :)

Что такое эстетически хороший способ сделать то, что я хочу сделать, что

  • без предупреждения
  • не включает трансляции
  • не слишком многословный

Надеюсь, я не ищу чего-то, чего не существует:)

4b9b3361

Ответ 1

Как вы уже отметили, проблема с условием i >= 0, когда он неподписан, заключается в том, что условие всегда истинно. Вместо вычитания 1 при инициализации i, а затем после каждой итерации вычитайте 1 после проверки условия цикла:

for (unsigned i = v.size(); i-- > 0; )

Мне нравится этот стиль по нескольким причинам:

  • Хотя i будет завернут до UINT_MAX в конце цикла, он не будет полагаться на это поведение - он будет работать одинаково, если типы были подписаны. Опираясь на неподписанную оболочку, я чувствую себя немного взломанной.
  • Он вызывает size() ровно один раз.
  • Он не использует >=. Всякий раз, когда я вижу этот оператор в цикле for, я должен его перечитать, чтобы удостовериться, что нет ошибки "один за другим".
  • Если вы измените интервал в условном выражении, вы можете использовать его "перейти к" оператору.

Ответ 2

Нет ничего, чтобы остановить цикл reverse_iterator, используя индекс, как описано в нескольких других ответах. Таким образом, вы можете использовать итератор или индекс по мере необходимости в части // do the work для минимальной дополнительной стоимости.

size_t index = v.size() - 1;
for(std::vector<SomeT>::reverse_iterator rit = v.rbegin(); 
    rit != v.rend(); ++rit, --index)
{
  // do the work
}

Хотя мне любопытно узнать, для чего нужен индекс. Доступ к v[index] совпадает с доступом к *rit.

Ответ 3

быть эстетически приятным!;)

for(unsigned i = v.size() - 1; v.size() > i; --i)

Ответ 4

Я бы предпочел вариант обратного итератора, потому что он все еще легко интерпретировать и позволяет избежать ошибок, связанных с индексами.

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

reverse_foreach (int value, vector) {
   do_something_with_the_value;
}

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

size_t i = 0;

foreach (int value, vector) {
   do_something;
   ++i;
}

Ответ 5

Попробуйте сделать, пока:

std::vector<Type> v;
// Some code 
if(v.size() > 0)
{
    unsigned int i = v.size() - 1;
    do
    {
        // Your stuff
    }
    while(i-- > 0);
}

Ответ 6

Привет, я думаю, что лучше использовать итератор, как вы используете в первом примере, и если вам нужно получить индекс итератора, вы можете использовать std:: distance, чтобы вычислить его, если я понимаю ваш вопрос

Ответ 7

Условие цикла i != std::numeric_limits<unsigned>::max()... или используйте UINT_MAX, если вы думаете, что он является подробным. или другим способом:
for(unsigned j=0, end=v.size(), i=end-1; j<end; --i, ++j)
или
for(unsigned end=v.size(), i=end-1; (end-i)<end; --i)

Ответ 9

Я думаю, что:

for(unsigned i = v.size() - 1; i >= 0; --i)

отлично, если вы отметили

!v.empty()

ранее.