5

Каковы преимущества std::distance по сравнению с вычитанием итераторов?

11

Я итерируюсь по вектору и мне нужен индекс, на который указывает итератор. Какие достоинства и недостатки у следующих методов?

  • it - vec.begin()
  • std::distance(vec.begin(), it)

5 ответ(ов)

7

Я бы предпочел использовать it - vec.begin(), именно по противоположной причине, указанной Навином: так код не скомпилируется, если вы замените вектор на список. Если делать это на каждой итерации, вы можете легко превратить алгоритм с временной сложностью O(n) в алгоритм с временной сложностью O(n^2).

Другой вариант, если вы не переходите по контейнеру во время итерации, — сохранить индекс как второй счетчик цикла.

Примечание: it — это распространенное название для итератора контейнера, std::container_type::iterator it;.

1

Я бы предпочел использовать std::distance(vec.begin(), it), так как это позволит мне сменить контейнер без необходимости вносить изменения в код. Например, если вы решите использовать std::list вместо std::vector, который не предоставляет итератор случайного доступа, ваш код все равно будет компилироваться. Поскольку std::distance автоматически выбирает оптимальный метод в зависимости от характеристик итераторов, у вас также не будет ухудшения производительности.

0

Как уже показали UncleBens и Naveen, у каждого из этих подходов есть свои весомые причины. Какой из них "лучше", зависит от того, какое поведение вы хотите получить: хотите ли вы гарантировать постоянное время выполнения, или допускаете переход на линейное время, когда это необходимо?

Выражение it - vec.begin() выполняется за постоянное время, но оператор - определён только для итераторов произвольного доступа, поэтому код вообще не скомпилируется, если вы используете итераторы списков, например.

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

Таким образом, ни один из этих методов не является однозначно "лучше". Используйте тот, который соответствует вашим требованиям.

0

Мне нравится этот вариант: it - vec.begin(), потому что, на мой взгляд, он четко показывает "расстояние от начала". С итераторами мы привыкли мыслить в терминах арифметики, поэтому знак - является самым очевидным индикатором в данном контексте.

0

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

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

  • Если вы используете явное вычитание, ваш алгоритм будет ограничен довольно узким классом итераторов: итераторами произвольного доступа. (Это то, что вы получаете от std::vector.)
  • Если вы используете std::distance, ваш алгоритм будет поддерживать гораздо более широкий класс итераторов: итераторы ввода.

Конечно, вычисление std::distance для не произвольно-доступных итераторов в общем случае является неэффективной операцией (в то время как для произвольно-доступных это так же эффективно, как вычитание). Вам решать, имеет ли ваш алгоритм смысл для не произвольно-доступных итераторов с точки зрения эффективности. Если потеря эффективности критична до такой степени, что делает ваш алгоритм совершенно бесполезным, то лучше придерживаться вычитания, тем самым предотвращая неэффективные применения и заставляя пользователя искать альтернативные решения для других типов итераторов. Если же эффективность с не произвольно-доступными итераторами все еще находится в приемлемых пределах, то лучше использовать std::distance и задокументировать тот факт, что алгоритм работает лучше с итераторами произвольного доступа.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь