STL ostream_iterator пишет на экран, хотя я перезаписал его? - PullRequest
0 голосов
/ 16 июня 2010

В моем коде у меня есть следующее:

ostream_iterator<double> doubleWriter(cout, " ~ ");
// ...
*doubleWriter = 1.1;
doubleWriter++;
*doubleWriter = 2.2;
*doubleWriter = 3.3; // shouldn't 2.2 be overwritten?
doubleWriter++;
*doubleWriter = 44.2;

cout << endl << endl;

Я ожидал, что он выведет это:

1.1 ~ 3.3 ~ 44.2 ~ 

Вместо этого был вывод:

1.1 ~ 2.2 ~ 3.3 ~ 44.2 ~ 

Почему это происходит?Мне кажется, что я перезаписываю 2.2 и вставляю 3.3 на месте, так как я не увеличивал.Увеличение является необязательным шагом?

Ответы [ 3 ]

3 голосов
/ 16 июня 2010

Для стандартного ostream_iterator оператор ++ (префикс и постфикс) не используется.Он ничего не делает и не имеет значения.

Нет необходимости делать ++ вручную, поскольку итератор всегда «продвигается», когда вы что-то выводите через него.1009 * По данным библиотеки Отчет о дефектах 485 , предполагалось, что назначение и приращение чередуются.Это требование, по-видимому, не вошло в текущую версию стандарта.Но в будущих ревизиях он будет включен.Другими словами, как уже отмечалось, правильным способом использования итератора вывода является чередование присваиваний и приращений.

3 голосов
/ 16 июня 2010

ostream_iterator является выходным итератором.
http://www.sgi.com/tech/stl/OutputIterator.html

Одним из требований итератора вывода является то, что между каждым присваиванием потоку используется оператор ++ (pre или post). Таким образом, неопределенное поведение - назначать потоку два раза подряд без увеличения итератора.

Dereference assignment:     *x = t

Pre-Conditions:             x is dereferenceable:

                            If there has been a previous assignment through x,
                            then there has been an intervening increment.

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

См. Семантика выражений для отмены назначения (предварительные условия). См. Также Примечание [3] на связанной странице выше.

Для официальной стандартной цитаты:

http://www.open -std.org / Jtc1 / sc22 / wg21 / docs / documents / 2010 / n3090.pdf (последний проект)
Раздел 24.2.4: Пункт 2 (выделено мной)

[Примечание: единственное допустимое использование оператора * находится слева от оператора присваивания. Назначение через одно и то же значение итератора происходит только один раз . Алгоритмы на выходных итераторах никогда не должны попытаться пройти через один и тот же итератор дважды. Они должны быть однопроходными алгоритмами. Равенство и Неравенство не может быть определено. Алгоритмы, которые принимают выходные итераторы, могут использоваться с ostreams как место для размещения данных через класс ostream_iterator, а также с помощью итераторов вставки и вставки указатели. —Конечная записка]

Я не согласен с интерпретацией дефектного отчета AndreyT 485:

а) что каждое значение выходного итератора записывается в: стандарт позволяет: ++ x; ++ х; ++ х;
б) что присваивания выходному итератору выполняются в порядке X a (x); ++ а; * А = 1; * Х = 2; разрешено
в) Цепочки выходных итераторов не могут быть построены: X a (x); ++ а; X b (а); ++ б; Х с (б); C ++; разрешено, и в соответствии с текущей формулировкой (я полагаю) x, a, b, c может быть записано в любом порядке.

Проблемы (а) и (с) не имеют отношения.
Проблема (b) относится к ситуациям, когда задействовано несколько итераторов.

Обратите внимание, что в (b) мы используем итератор a (копия x) и итератор x. Недостаток в том, что текущий стандарт не требует, чтобы «x» увеличивался перед использованием; после того, как «а» был назначен через. Что не является ситуацией в этом контексте.

0 голосов
/ 16 июня 2010

Поведение итератора ostream - всегда перемещать выходную позицию.Это то, что вы обычно хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...