Но погодите, нужно быть аккуратными после выполнения операции инкремента и до разыменования. При it==end
выполнилось, то мы дошли до последнего введенного слова.
Конечный итератор — это экземпляр std::istream_iterator
, созданный с помощью стандартного конструктора без параметров. Он нужен для сравнения в условии остановки, проверяемом на каждой итерации цикла:
istream_iterator
Как только std::cin
окажется пустым, итератор it
true
.
std::inserter
Мы использовали пару итераторов it
и end
как std::copy
. Третий параметр должен быть итератором для работы с выходными данными. Здесь мы не можем просто взять итератор s.begin()
или s.end()
. Для пустого множества они будут одинаковыми, так что нам даже нельзя
Тут вступает в дело std::inserter
. Это функция, возвращающая итератор std::insert_iterator
, который ведет себя как итератор, но при этом делает что-то отличное от того, что делают обычные итераторы. Выполнение операции инкремента для данного итератора ничего не даст. Когда мы его разыменовываем и присваиваем значение, он берет контейнер, прикрепленный к нему, и
При создании экземпляра std::insert_iterator
с помощью std::inserter
вам понадобятся два параметра:
auto insert_it = inserter(s, s.end());
Здесь s
— наше множество, а s.end()
— итератор, указывающий на место, куда должен быть вставлен новый элемент. Для пустого множества, с которого и начинается наш пример, этот итератор эквивалентен s.begin()
. В других структурах данных наподобие векторов или списков второй параметр критически важен при определении того, куда именно итератор вставки должен добавить новые элементы.
Собираем все воедино
В конце концов все волшебство происходит во время вызова метода std::copy
:
copy(input_iterator_begin, input_iterator_end, insert_iterator);
Данный вызов получает следующий токен слова из потока std::cin
с помощью входного итератора и помещает его в контейнер std::set
. После этого он инкрементирует оба итератора и проверяет, равен ли входной итератор конечному. Если это не так, то в потоке ввода еще остаются слова, так что все
Повторяющиеся слова отбрасываются автоматически. При наличии в множестве конкретного слова повторное его добавление std::set
отличается от std::multiset
, куда можно вставить повторяющиеся записи.
Реализуем простой ОПН-калькулятор с использованием контейнера std::stack
Класс std::stack
— класс-адаптер, который позволяет помещать
ОПН — это нотация, которая может служить для записи математических выражений таким образом, чтобы их было проще анализировать. В ОПН выражение 1 + 2
выглядит как 1 2 +
. Сначала идут операнды, а затем — оператор. Еще один пример: выражение (1 + 2) * 3
в ОПН выглядит как 1 2 + 3 *
, оно уже показывает, почему подобные выражения проще анализировать, и нам не нужны скобки, чтобы определить подвыражения (рис. 2.4).
Как это делается
В этом примере мы считаем математическое выражение, записанное в формате ОПН, из стандартного потока ввода, а затем передадим его в функцию, которая вычислит его значение. Наконец, выведем на экран численный результат.
1. Мы будем использовать множество вспомогательных объектов из STL, поэтому сначала разместим несколько директив включения:
#include
#include
#include
#include
#include
#include
#include
#include
#include
2. Мы также объявляем, что используем пространство имен std
, чтобы сэкономить немного времени, которое ушло бы на набор текста:
using namespace std;