Как * это ++ действительно для выходных итераторов? - PullRequest
12 голосов
/ 23 октября 2010

В примере кода я часто вижу код, такой как *it++, для выходных итераторов. Выражение *it++ делает копию it, увеличивает it, а затем возвращает копию, на которую в конечном итоге разыменовывается Насколько я понимаю, создание копии выходного итератора делает источник недействительным. Но тогда приращение it, которое выполняется после создания копии, будет недопустимым, верно? Является ли мое понимание выходных итераторов ошибочным?

Ответы [ 5 ]

14 голосов
/ 23 октября 2010

Стандарт требует, чтобы *r++ = t работал для выходных итераторов (24.1.2).Если это не работает, это не выходной итератор по определению стандарта.

Именно реализация итератора должна гарантировать, что такие операторы работают должным образом.

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

Именно поэтому *r++ = t работает.Копия сделана из исходного итератора, исходный итератор разыменован, и копия увеличивается.Исходный итератор больше никогда не будет использоваться, и копия больше не ссылается на то же значение.

6 голосов
/ 23 октября 2010

Выражение *it++ делает не (должно) копировать его, не увеличивает его и т. Д. Это выражение действительно только для удобства, как следуетобычная семантика.Только operator= делает реальную работу.Например, в g ++ реализации ostream_iterator, operator*, operator++ и operator++(int) делают только одну вещь: return *this (другими словами, ничего!).Мы могли бы написать, например:

it = 1;
it = 2;
*it = 3;
++it = 4;

Вместо: *it++ = 1; *it++ = 2; *it++ = 3; *it++ = 4;

1 голос
/ 23 октября 2010

Глядя на ваш комментарий, кажется, что большая часть путаницы возникает из документации SGI, которая, я бы сказал, немного вводит в заблуждение по этому вопросу.

Копирование выходного итератора не делает недействительным скопированный итератор. Реальное ограничение довольно простое: вы должны разыменовать заданное значение выходного итератора только один раз. Однако иметь две копии за раз - это хорошо, если вы разыменуете только одну из них, если они имеют одинаковое значение. В случае, подобном тому, где вы разыменовываете одно, затем выбрасываете его значение и увеличиваете другое, но разыменовываете его только после того, как увеличение произошло, все это прекрасно.

1 голос
/ 23 октября 2010

Выходные итераторы просто не работают как обычные итераторы, и их интерфейс указан так, что их можно использовать в выражениях, подобных указателям (*it++ = x), с полезными результатами.operator++() и operator++(int) все возвращают *this в качестве эталонных и выходных итераторов, имеют магию operator=, которая выполняет ожидаемую операцию вывода.Поскольку вы не можете читать из выходного итератора, тот факт, что operator*() и т. Д., Не работают, как для других итераторов, не имеет значения.

0 голосов
/ 23 октября 2010

Разве итератор не просто указатель?Инкремент, затем разыменование это просто переходит к следующему элементу.

...