Получить индекс в векторе, используя итераторы - PullRequest
5 голосов
/ 25 сентября 2008

При переборе элементов вектора предпочтительно использовать итераторы вместо индекса (см. Зачем использовать итераторы вместо индексов массива? ).

std::vector<T> vec;
std::vector<T>::iterator it;
for ( it = vec.begin(); it != vec.end(); ++it )
{
   // do work
}

Однако может понадобиться использовать индекс в теле цикла. Что из следующего было бы предпочтительнее в этом случае, учитывая производительность и гибкость / расширяемость?

  1. Возврат к индексированному циклу
    std::vector vec;
    size_t i;
    for ( i = 0; i < vec.size(); ++i )
    {
       // use i
    }
    
  2. Рассчитать смещение
    std::vector vec;
    std::vector::iterator it;
    for ( it = vec.begin(); it != vec.end(); ++it )
    {
       size_t i = it - vec.begin(); 
       // use i
    }
    
  3. Использовать std :: distance
    std::vector vec;
    std::vector::iterator it;
    for ( it = vec.begin(); it != vec.end(); ++it )
    {
       size_t i = std::distance( vec.begin(), it );
       // use i
    }
    

Ответы [ 7 ]

13 голосов
/ 25 сентября 2008

Если вы планируете использовать исключительно вектор, вы можете захотеть вернуться к индексированному циклу, поскольку он передает ваше намерение более четко, чем цикл итератора. Однако, если развитие вашей программы в будущем может привести к изменению контейнера, вам следует придерживаться итераторов и использовать std :: distance, что гарантированно работает со всеми стандартными итераторами.

8 голосов
/ 25 сентября 2008

Использование std :: distance является более общим, поскольку оно работает для всех итераторов, а не только для итераторов с произвольным доступом И он должен быть таким же быстрым, как It - vec.begin () в случае итераторов с произвольным доступом.

Это - vec.begin () в основном является арифметикой указателей.

6 голосов
/ 25 сентября 2008

std::distance(vec.begin(), it) даст вам индекс, на который указывает it, при условии, что он указывает на vec.

Карл

4 голосов
/ 25 сентября 2008

Вернуться к индексированному циклу.

В основном в 90% случаев итераторы превосходят их, это один из тех 10%. Используя итератор, вы делаете код более сложным и, следовательно, более сложным для понимания, когда основной причиной использования итератора в первую очередь было упрощение кода.

1 голос
/ 25 сентября 2008

Вам не хватает одного решения: сохраняйте индекс на случай, если он вам нужен, но не используйте его как условие цикла. Работает и со списками, а затраты (за цикл) составляют O (n) и дополнительный регистр.

0 голосов
/ 25 сентября 2008

Для векторов я всегда использую целочисленный метод. Каждый индекс в векторе имеет ту же скорость, что и поиск в массиве. Если я собираюсь часто использовать значение, для удобства я создаю ссылку на него.

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

Я использую итераторы для других типов контейнеров, а иногда, когда вам не нужна переменная цикла. Но если вам нужна переменная цикла, вы ничего не делаете, кроме как сделать цикл более трудным для ввода. (Я не могу дождаться автоматического запуска c ++ 0x ..)

0 голосов
/ 25 сентября 2008

Я бы всегда склонялся к использованию итераторов для будущих целей разработки.

В приведенном выше примере, если вы, возможно, решили поменять std :: vector на std :: set (возможно, вам нужна уникальная коллекция элементов), использование итераторов и distance () продолжит работать.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...