[БЕЗ_ЗВУКА] Продемонстрируем, что итераторы универсальнее чем range-based for, что их можно использовать в гораздо более широком числе случаев. Как я это продемонстрирую? Давайте я вернусь к множеству языков, словарь пока уберу. [ЗВУК] И снова сделаю множество строк [ЗВУК] с языками. Снова Python, C++, C, Java и C#. Давайте я выведу с помощью итераторов это множество. Наверное, даже проще будет с вектором. Этот вектор выведу в обратном порядке. Как это можно сделать с помощью итераторов? Логично было бы ожидать, на самом деле, что если у меня... Я подключу сейчас модуль vector. Логично было бы ожидать, что если у меня у итераторов есть ++, который двигает их на следующий элемент, то есть и −−, который двигает на предыдущий. Давайте попробуем. Наверное, цикл for нам тут уже не поможет. Я изначально... Мне нужно начать с конца итерироваться, поэтому я начну с end от langs, и теперь у меня будет некий цикл while, условия которого я пока не придумал. В этом цикле мы будем выводить очередной элемент, ну, скажем, через пробел. И теперь давайте думать. Мы хотим как-то двигать этот итератор в обратную сторону, делать от него −−. Если я сделаю −−it вот здесь, то у меня цикл начнется с того, что попробует обратиться к end, к элементу, который лежит под end. Так делать нельзя, поэтому наверное, надо делать −−it, декрементировать итератор в начале. Тогда условие, наверное, должно быть таким: как только у меня итератор стал равен begin от langs, я уже не могу делать от него −−, поэтому должен закончить. Давайте я попробую этот код скомпилировать и проверить, что я все правильно написал. Компилируем, запускаем, и у меня языки вывелись в обратном порядке. Все работает. Давайте подробнее разберемся, как это все происходит. Итак, изначально итератор указывает на конец вектора, точнее, даже за концом. Я проверяю, что он не begin, поэтому могу зайти внутрь цикла, подвинуть его теперь уже на последний элемент вектора и вывести этот последний элемент. Затем опять же проверяю, что у меня все еще не begin, двигаю обратно влево, вывожу, двигаю, вывожу. Подвинул на begin, опять же вывел, пока все хорошо. Затем я вижу, что у меня итератор указывает на begin, равен begin, поэтому я уже не могу сделать −−. Цикл while завершается, все. Мы вывели наш вектор в обратном порядке. А такой вопрос: вот смотрите, мы внутри цикла делали −− итератор. И у нас условие уже было, этот самый итератор. Зная постфиксные операторы, инкременты и декременты, вы можете захотеть вынести этот декремент, как показано на слайде, в условие цикла. То есть написать там while (it−− != begin(langs)) Какая будет разница между изначальным циклом, который мы написали, и циклом с этим декрементом в условии? Оказывается, разница лишь в одном. Вы, когда итератор уже стал указывать на begin, вы, конечно, из цикла выйдете, но все-таки сделаете к нему −−. Вот этого делать нельзя, это опасно. Перед begin нет никаких итераторов. Компилятор имеет право, если вы от begin сделали −−, сделать все, что угодно. Это очень опасно, делать так не надо. Итак, какие у нас есть опасные операции над итераторами. Это, во-первых, *end, мы видели, что у нас программа падает в этом случае. И операции, при которых программа может упасть, а может и не упасть: это увеличение end — за end нет вообще ничего, и уменьшение begin — перед begin тоже ничего нет. У внимательных слушателей мог возникнуть вопрос: чем отличаются итераторы от ссылок? Казалось бы, и те, и другие указывают на элементы. И ссылки, когда мы передавали в функцию, у нас элементы не копировались, и итераторы тоже можно было дешево передавать в функции. В чем же разница? А разницу, на самом деле, мы уже прочувствовали. Во-первых, итераторы могут указывать на end, то есть как бы в никуда. С помощью итераторов можно сказать, что элемента там нет, а ссылка всегда указывает на конкретный элемент. Мы не можем создать ссылку, не привязав ее ни к чему. И во-вторых, когда мы ссылку к чему-то привязали, она не может переместиться уже на какой-то другой элемент. А итераторы, к ним можно делать ++. Вот как мы видим на примере на слайде, если вы к итератору сделаете ++, он подвинется на следующий элемент. А если вы к ссылке сделаете ++, то если это число, то оно само увеличится на 1, ссылка никуда не подвинется. Итак, что мы узнали из этого видео? Мы узнали, что итераторы есть у всех контейнеров, которые мы знаем: у векторов, у строк, у множеств, у словарей. И итераторы предоставляют универсальный интерфейс, это называется универсальный способ итерироваться по этим контейнерам. Но правда, если вы можете использовать range-based for, используйте его, потому что все-таки итераторы более мощная вещь, и код с ними получается менее понятный.