Я перебираю вектор и мне нужен индекс, на который в данный момент указывает итератор. AFAIK это можно сделать двумя способами:
it - vec.begin()
std::distance(vec.begin(), it)
Каковы плюсы и минусы этих методов?
c++
iterator
coding-style
cairol
источник
источник
it
?std::container_type::iterator it;
std::list
что не предлагает прямой доступ к элементам по их положению, поэтому, если вы не можете этого сделатьlist[5]
, вы не сможете этого сделатьlist.begin() + 5
.Я бы предпочел, так
std::distance(vec.begin(), it)
как это позволит мне изменить контейнер без каких-либо изменений кода. Например, если вы решите использоватьstd::list
вместоstd::vector
которого не предоставляет итератор произвольного доступа, ваш код все равно будет компилироваться. Поскольку std :: distance выбирает оптимальный метод в зависимости от характеристик итератора, у вас также не будет никакого снижения производительности.источник
vec
- плохая новость. Если код был переписан так, чтобы он был универсальным, принимая тип контейнера в качестве параметра шаблона, тогда мы можем (и должны) поговорить об обработке итераторов без произвольного доступа ;-)vec
тоже довольно плохая новость.Как показали UncleBens и Naveen, для этого есть веские причины. Какой из них «лучше», зависит от того, какое поведение вы хотите: хотите ли вы гарантировать поведение в постоянном времени, или вы хотите, чтобы оно при необходимости возвращалось к линейному времени?
it - vec.begin()
занимает постоянное время, ноoperator -
определяется только на итераторах с произвольным доступом, поэтому, например, код вообще не будет компилироваться с итераторами списка.std::distance(vec.begin(), it)
работает для всех типов итераторов, но будет работать только в постоянном времени, если используется на итераторах с произвольным доступом.Ни один из них не "лучше". Используйте тот, который делает то, что вам нужно.
источник
Мне нравится этот
it - vec.begin()
, потому что мне ясно сказано «расстояние от начала». С итераторами мы привыкли мыслить в терминах арифметики, поэтому-
знак является самым ясным индикатором здесь.источник
distance
?it++
а не что-то вродеstd::increment(it)
, не так ли? Разве это не считается менее понятным?++
Оператор определяется как часть STL последовательностей , как , как мы увеличиваем итератор.std::distance
вычисляет количество элементов между первым и последним элементом. Тот факт, что-
оператор работает, просто совпадение.Если вы уже ограничены / зашиты ваш алгоритм с использованием
std::vector::iterator
иstd::vector::iterator
только, это действительно не имеет значения , какой метод вы будете в конечном итоге с помощью. Ваш алгоритм уже конкретизирован за пределами точки, где выбор одного из других может иметь любое значение. Они оба делают одно и то же. Это просто вопрос личных предпочтений. Я бы лично использовал явное вычитание.Если, с другой стороны, вы хотите сохранить более высокую степень универсальности в вашем алгоритме, а именно, чтобы дать возможность того, что когда-нибудь в будущем он может быть применен к какому-либо другому типу итератора, тогда лучший метод зависит от вашего намерения , Это зависит от того, насколько вы хотите ограничить тип итератора, который можно использовать здесь.
Если вы используете явное вычитание, ваш алгоритм будет ограничен довольно узким классом итераторов: итераторами с произвольным доступом. (Это то, что вы получаете сейчас
std::vector
)Если вы используете
distance
, ваш алгоритм будет поддерживать гораздо более широкий класс итераторов: входные итераторы.Конечно, вычисление
distance
для итераторов без произвольного доступа в общем случае является неэффективной операцией (хотя, опять же, для произвольных итераторов это так же эффективно, как вычитание). Вам решать, имеет ли ваш алгоритм смысл для итераторов без произвольного доступа с точки зрения эффективности. Если результирующая потеря эффективности опустошает вас до такой степени, что делает ваш алгоритм совершенно бесполезным, тогда вам лучше придерживаться вычитания, что запрещает неэффективное использование и вынуждает пользователя искать альтернативные решения для других типов итераторов. Если эффективность с итераторами без произвольного доступа все еще находится в пригодном для использования диапазоне, то вам следует использоватьdistance
и задокументировать тот факт, что алгоритм лучше работает с итераторами с произвольным доступом.источник
Согласно http://www.cplusplus.com/reference/std/iterator/distance/ , поскольку
vec.begin()
это итератор с произвольным доступом , метод расстояния использует-
оператор.Таким образом, ответ с точки зрения производительности - то же самое, но, возможно, использование
distance()
легче понять, если кому-то придется читать и понимать ваш код.источник
Я бы использовал
-
вариантstd::vector
только - довольно ясно, что имеется в виду, и простота операции (которая не больше, чем вычитание указателя) выражается синтаксисом (distance
с другой стороны, звучит как пифагор на первое чтение, не так ли?) Как указывает UncleBen,-
также действует как статическое утверждение на случай, еслиvector
он случайно изменился наlist
.Кроме того, я думаю, что это гораздо более распространено - хотя у меня нет цифр, чтобы доказать это. Основной аргумент:
it - vec.begin()
короче в исходном коде - меньше печатной работы, меньше занимаемого места. Поскольку ясно, что правильный ответ на ваш вопрос сводится к вкусу, это также может быть веским аргументом.источник
Вот пример, чтобы найти «все» вхождения 10 вместе с индексом. Думаю, это поможет.
источник