Почему "! =" Используется с итераторами?

Я использую такие петли, как это:

for (std::size_t Index = 0; Index < Foo.Size(); Index++)
{
    // Do stuff with Foo[Index].
}

Но когда я вижу петли итератора в коде других, они выглядят так:

for (Bar::Iterator Iterator = Foo.Begin(); Iterator != Foo.End(); Foo++)
{
    // Do stuff with *Iterator.
}

Я считаю, что Iterator != Foo.End() отклоняется. Это также может быть опасно, если Iterator увеличивается на несколько единиц.

Кажется более "правильным" использовать Iterator < Foo.End(), но я никогда не вижу этого в реальном коде. Почему бы и нет?

Ответ 1

Все итераторы равны друг другу. Только итераторы с произвольным доступом сравнимы по аналогии. Итераторы ввода, форвардные итераторы и двунаправленные итераторы не являются сравнимо сопоставимыми.

Таким образом, сравнение с использованием != является более общим и гибким, чем сравнение с использованием <.


Существуют разные категории итераторов, поскольку не все диапазоны элементов имеют одинаковые свойства доступа. Например,

  • если у вас есть итераторы в массив (непрерывная последовательность элементов), это тривиально, чтобы относительно сравнить их; вам просто нужно сравнить индексы указателей на элементы (или указатели на них, поскольку итераторы, вероятно, просто содержат указатели на элементы);

  • если у вас есть итераторы в связанном списке, и вы хотите проверить, является ли один итератор "меньше" другого итератора, вам нужно пройти узлы связанного списка с одного итератора, пока вы не достигнете другого итератор или вы дойдете до конца списка.

Правило состоит в том, что все операции над итератором должны иметь постоянную временную сложность (или, как минимум, сублинейную временную сложность). Вы всегда можете выполнять сравнение равенства в постоянное время, так как вам просто нужно сравнить, указывают ли итераторы на один и тот же объект. Таким образом, все итераторы эквивалентны равенству.


Кроме того, вам не разрешается увеличивать итератор за конец диапазона, на который он указывает. Итак, если вы закончите сценарий, в котором it != foo.end() не делает то же самое, что и it < foo.end(), у вас уже есть поведение undefined, потому что вы прошли через конец диапазона.

То же самое верно для указателей в массиве: вам не разрешается увеличивать указатель за пределами одного конца массива; программа, которая делает это, демонстрирует поведение undefined. (То же самое, очевидно, неверно для индексов, так как индексы являются целыми числами.)

Некоторые реализации стандартной библиотеки (например, реализация стандартной библиотеки Visual С++) имеют полезный код отладки, который будет вызывать утверждение, когда вы делаете что-то незаконное с таким итератором.

Ответ 2

Короткий ответ: поскольку Iterator не является числом, это объект.

Более длинный ответ: Есть больше коллекций, чем линейных массивов. Деревья и хеши, например, действительно не поддаются "этому индексу до этого другого индекса". Например, для дерева два индекса, которые живут на отдельных ветвях. Или любые два индекса в хеше - они вообще не имеют порядка, поэтому любой порядок, который вы налагаете на них, произволен.

Вам не нужно беспокоиться о "пропуске" End(). Это также не число, это объект, который представляет конец коллекции. Не имеет смысла иметь итератор, который проходит мимо него, и в действительности он не может.

Ответ 3

bool solve(){
    map<int,int>::iterator a,b;
    return a<b;
}

Результат:

ошибка: нет соответствия для 'operator < в 'a < б