Разыменование-назначение для дважды увеличенного OutputIterator

В соответствии с (отличным) вопросом требования к пост-инкременту C++ OutputIterator мы наблюдаем, что для разыменовываемое и увеличиваемое значение r из OutputIterator типа X и значение o соответствующего типа, выражение

*r++ = o;

действителен и имеет семантику, эквивалентную

X a(r);
++r;
*a = o;

Однако остается ли a присваиваемым по разыменованию, если r увеличивалось более одного раза за промежуточный период; то есть этот код действителен?

X a(r);
++r;
++r;
*a = o;

Трудно понять, как операции над значением могут повлиять на достоверность операций над другим значением, но, например. InputIterator (24.2.3) имеет в постусловиях ++r:

Любые копии предыдущего значения r больше не должны быть разыменованными или находиться в домене ==.

Соответствующие разделы: 24.2.2 Итератор, 24.2.4 Итераторы вывода, 17.6.3.1 Требования к аргументам шаблона.

Кроме того, если это не требуется, чтобы быть действительным, существуют ли какие-либо ситуации, когда использование его недопустимости помогло бы в реализации (с точки зрения эффективности, простоты) типа OutputIterator при соблюдении существующих требований?


person ecatmur    schedule 09.08.2012    source источник
comment
SGI STL (sgi.com/tech/stl/OutputIterator.html сноска 3 ) явно запрещает такое поведение, вызывая последовательность чередующихся приращений и разыменований-назначений; однако я не могу вывести это требование из стандарта С++. Означает ли «только один раз» в [24.2.4:2] ровно один раз или не более одного раза?   -  person nknight    schedule 09.08.2012
comment
Этот ответ: (stackoverflow.com/a/4004035/985943) заставляет меня думать, что такое поведение допустимо для ostream_iterator, который фактически увеличивается только при назначении, игнорируя другие операции увеличения. Однако не похоже, что все OutputIterators должны подчиняться этой семантике.   -  person nknight    schedule 09.08.2012
comment
@nknight очень интересно. только один раз встречается в стандарте 5 раз, в 3.4:1 с другим значением и в 5.17:7, 12.8:15, 29.6.5:8 в смысле не более одного раза ( но обычно один раз). ровно один раз и не более одного раза появляются 5 раз. Конечно, если бы стандарт предусматривал ограничения SGI, они бы включили этот язык?   -  person ecatmur    schedule 09.08.2012
comment
На самом деле похоже, что кто-то нашел это в 2004 году: (open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#485) и формулировка в n3066 (open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3066.html) кажется, подтверждает требование чередования приращения/разыменования, не так ли? Странно, что это не попало в мою копию 14882:2011, в то время как остальная часть n3066 попала (насколько я могу судить).   -  person nknight    schedule 13.08.2012
comment
@nknight и еще немного копания выявили дефект 2035, который был поднят после появления n3225 без исправлений от n3066. Таким образом, намерение стандарта ясно, просто он не попал вовремя в опубликованную версию. Отправьте как ответ, и я приму.   -  person ecatmur    schedule 13.08.2012


Ответы (1)


Эта проблема была поднята в 2004 г. как дефект 485, а формулировка в n3066 уточняет проблема, требующая, чтобы итератор вывода поддерживал только последовательность чередующихся приращений и разыменования/назначения. Таким образом, в вашем примере r не нужно увеличивать после первого ++r, если только нет промежуточного разыменования/назначения. Это поведение также требуется STL SGI (см. сноску 3). Как вы упомянули выше, n3225 появился без исправлений от n3066, поэтому дефект 2035 возник; но, увы, исправление не вошло в опубликованную версию C++11 (ISO/IEC 14882:2011).

Кроме того, дефект 2035 говорит о том, что a (из X a(r++);) нельзя использовать как *a = 0:

«После этой операции [т.е. ++r] r не требуется увеличивать, и любые копии предыдущего значения r больше не требуется разыменовывать или увеличивать».

Есть ситуации, когда это может помочь в реализации (с точки зрения простоты): см., например. этот вопрос на ostream_iterator, где такие (недопустимые) двойные приращения игнорируются, просто возвращая *this; только разыменование/присваивание приводит к фактическому увеличению ostream_iterator.

person nknight    schedule 13.08.2012