Я повторяю вектор и нуждаюсь в индексе, на который указывает итератор. AFAIK это можно сделать двумя способами:
-
it - vec.begin()
-
std::distance(vec.begin(), it)
Каковы плюсы и минусы этих методов?
Я повторяю вектор и нуждаюсь в индексе, на который указывает итератор. AFAIK это можно сделать двумя способами:
it - vec.begin()
std::distance(vec.begin(), it)
Каковы плюсы и минусы этих методов?
Я бы предпочел it - vec.begin()
именно по той противоположной причине, которую дал Naveen: поэтому он не будет компилироваться, если вы измените вектор на список. Если вы делаете это на каждой итерации, вы можете легко превратить алгоритм O (n) в алгоритм O (n ^ 2).
Другой вариант, если вы не прыгаете в контейнере во время итерации, будет поддерживать индекс как второй счетчик циклов.
Примечание: it
общее имя для итератора контейнера, std::container_type::iterator it;
,
Я бы предпочел std::distance(vec.begin(), it)
, так как это позволит мне изменить контейнер без каких-либо изменений кода. Например, если вы решили использовать std::list
вместо std::vector
, который не предоставляет итератор с произвольным доступом, ваш код все равно будет компилироваться. Поскольку std:: distance выбирает оптимальный метод в зависимости от характеристик итератора, вы также не будете иметь ухудшения производительности.
Как показали UncleBens и Naveen, для обоих есть веские причины. Какой из них "лучше" зависит от того, какое поведение вы хотите: хотите ли вы гарантировать постоянное поведение или хотите ли вы вернуться к линейному времени, когда это необходимо?
it - vec.begin()
принимает постоянное время, но operator -
определяется только для итераторов произвольного доступа, поэтому код вообще не будет компилироваться с итераторами списков.
std::distance(vec.begin(), it)
работает для всех типов итераторов, но будет выполняться только операция с постоянным временем, если используется для итераторов произвольного доступа.
Ни один из них не "лучше". Используйте тот, который делает то, что вам нужно.
Мне нравится этот: it - vec.begin()
, потому что для меня это четко говорит "расстояние от начала". С итераторами мы привыкли думать в терминах арифметики, поэтому знак -
является самым ярким индикатором здесь.
Если вы уже ограничены/жестко закодированы алгоритмом использования только std::vector::iterator
и std::vector::iterator
, на самом деле не имеет значения, какой метод вы будете использовать. Ваш алгоритм уже конкретизирован за пределами того места, где выбор одного из других может иметь какое-либо значение. Они оба делают то же самое. Это только вопрос личных предпочтений. Я лично использовал бы явное вычитание.
Если, с другой стороны, вы хотите сохранить более высокую степень общности в своем алгоритме, а именно, чтобы позволить возможность, что когда-нибудь в будущем она может быть применена к другому типу итератора, тогда лучший способ зависит по вашим намерениям. Это зависит от того, насколько ограничительным вы хотите быть в отношении типа итератора, который можно использовать здесь.
Если вы используете явное вычитание, ваш алгоритм будет ограничен довольно узким классом итераторов: итераторы с произвольным доступом. (Это то, что вы получаете от std::vector
)
Если вы используете distance
, ваш алгоритм будет поддерживать гораздо более широкий класс итераторов: входные итераторы.
Конечно, вычисление distance
для итераторов неслучайного доступа - это в общем случае неэффективная операция (в то время как для случайного доступа она эффективна как вычитание). Вам решать, нужен ли ваш алгоритм для итераторов без случайного доступа, с точки зрения эффективности. Это приводит к потере эффективности, что приводит к тому, что ваш алгоритм полностью бесполезен, поэтому лучше придерживаться вычитания, тем самым запрещая неэффективное использование и заставляя пользователя искать альтернативные решения для других типов итераторов. Если эффективность с итераторами неслучайного доступа все еще находится в допустимом диапазоне, то вы должны использовать distance
и документировать тот факт, что алгоритм работает лучше с итераторами с произвольным доступом.
В соответствии с http://www.cplusplus.com/reference/std/iterator/distance/, поскольку vec.begin()
является итератором произвольного доступа, метод расстояния использует оператор -
.
Итак, ответ с точки зрения производительности один и тот же, но, возможно, использование distance()
проще понять, если кто-то должен будет читать и понимать ваш код.
Я бы использовал вариант -
только для std::vector
- довольно ясно, что имеется в виду, а простота операции (которая не превышает вычитание указателя) выражается синтаксисом (, с другой стороны, звучит как пифагор в первом чтении, не так ли?). Как указывает UncleBen, -
также действует как статическое утверждение в случае, когда vector
случайно изменено на list
.
Кроме того, я думаю, что это гораздо более распространено - не имеют числа, чтобы доказать это. Главный аргумент: it - vec.begin()
короче в исходном коде - меньше печатается, меньше потребляется. Поскольку ясно, что правильный ответ на ваш вопрос сводится к тому, чтобы быть вопросом вкуса, это также может быть веским аргументом.