2010-03-25 2 views

ответ

6

Все стандартные контейнеры обеспечивают концепцию итератора. Итератору известно, как найти следующий элемент в контейнере, особенно если базовая структура не похожа на массив. Array-style operator[] не предоставляется каждым контейнером, поэтому привыкание использовать итераторы сделает более последовательный код, независимо от выбранного вами контейнера.

3

Вы можете абстрагироваться от реализации коллекции.

14

Предполагаю, что вы говорите об использовании вектора, не так ли?

Главное преимущество заключается в том, что код итератора работает для всех stl-контейнеров, в то время как оператор индексирования массива [] доступен только для векторов и требований. Это означает, что вы можете изменить базовый контейнер, если вам не нужно перекодировать каждый цикл. Это также означает, что вы можете поместить свой итерационный код в шаблон, и он будет работать для любого контейнера, а не только для классов и векторов (и, конечно же, массивов).

+0

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

+2

Оператор [] также может скрывать сколь угодно сложные операции. – Ryan

+0

Итак, только если мы используем структуры данных, отличные от массивов, лучше всего использовать итераторы? – PrithviRaj

2

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

1

Как и в других ответах, итераторы также могут быть быстрее (особенно по сравнению с operator[]), поскольку они по сути являются итерацией указателем. Если вы делаете что-то вроде:

for (int i = 0; i < 10; ++i) 
{ 
    my_vector[i].DoSomething(); 
} 

Каждая итерация цикла излишне вычисляет my_vector.begin() + i. Если вы используете итераторы, приращение итератора означает, что оно уже указывает на следующий элемент, поэтому вам не нужен этот дополнительный расчет. Это небольшая вещь, но она может повлиять на жесткие петли.

+0

Нет, простой' + 'редко занимает много циклов. – kennytm

+0

Все проведенные тесты указывают на отсутствие реальной разницы в скорости между итераторами и оп [] для векторов. Во всяком случае, op [] немного быстрее. – 2010-03-25 13:17:19

+0

@Neil: Я также проверил это и пришел к выводу, что итераторы * слегка * быстрее. Вы правы, хотя «нет никакой реальной разницы». И я уверен, что это зависит от реализации. Вероятно, вы тестировали на том, где итераторы не были оптимально реализованы ... – 2010-03-25 13:29:21

2

Для расширения на предыдущих ответы:

  1. Записи цикла с оператором [] ограничивающими вы в контейнер, который поддерживает [] и использует тот же тип индекса/размера. В противном случае вам нужно будет переписать каждый цикл, чтобы изменить контейнер.

  2. Даже если ваш контейнер поддерживает [], он может оказаться не оптимальным для последовательного перемещения. [] является в основном оператором произвольного доступа, который является O (1) для вектора, но может быть столь же плохим, как O (n), в зависимости от базового контейнера.

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

2

STL содержит алгоритмы, такие как transform и for_each, которые работают в контейнерах. Они не принимают индексы, но используют итераторы.

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

1

Еще одно небольшое отличие состоит в том, что вы не можете использовать erase() для элемента в векторе по индексу, у вас должен быть итератор. Нет ничего страшного, так как вы всегда можете сделать «vect.begin() + index» как ваш итератор, но есть и другие соображения. Например, если вы это сделаете, вы всегда должны проверять свой индекс на size(), а не на какую-то переменную, которую вы присвоили этому значению.

Ничего из этого не стоит особо беспокоиться, но, если у вас есть выбор, я предпочитаю доступ к итератору по причинам, указанным выше, и этим.

1

Я бы сказал, что это скорее вопрос согласованности и повторного использования кода.

  • Последовательность в том, что вы будете использовать все другие контейнеры с итераторами
  • код повторно в том, что алгоритмы, написанном для итераторов не может использоваться с оператором индекса, и наоборот ... и STL имеет много алгоритмов, поэтому вы определенно хотите опираться на него.

Наконец, я хотел бы сказать, что даже массивы C имеют итераторы.

const Foo* someArray = //... 
const Foo* otherArray = new Foo[someArrayLength]; 

std::copy(someArray, someArray + someArrayLength, otherArray); 

iterator_traits класс специализируется так, что указатели или модель RandomAccessIterator.