Получите индекс в вектор с помощью итераторов

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

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

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

  1. Вернуться к проиндексированному циклу
  2. Рассчитать смещение
  3. Используйте std :: distance
    std::vector vec;
    size_t i;
    for ( i = 0; i < vec.size(); ++i )
    {
       // use i
    }
    
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
0
4 582
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

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

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

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

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

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

Guvante 25.09.2008 13:39

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

QBziZ 25.09.2008 13:44

Кроме того, итераторы std :: map или std :: set далеко не глупы. Если бы я перебрал все возможные ключи, это, вероятно, заняло бы вечность. Кроме того, мне пришлось бы выполнять поиск O (log (n)) для каждого ключа. Таким образом, мой цикл займет O (m * log (n)). Используя итератор, я мог перебрать коллекцию за время O (n).

Doug T. 25.09.2008 16:18
Ответ принят как подходящий

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

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

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

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

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

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

Карл

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

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

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

Другие вопросы по теме