Для итераторов ввода, почему a == b не означает ++ a == ++ b?
§24.1.1/3 из С++ 03 Стандартные читает,
Для итераторов ввода a == b не подразумевает ++ a == ++ b. (Equality does not гарантируют заменяющее имущество или реляционная прозрачность.) Алгоритмы на входных итераторах никогда не следует пытаться пройти через те же итератора дважды. Они должны быть одиночными проходных алгоритмов. Тип значения T не должен быть назначаемым типом (23.1). Эти алгоритмы могут быть использованы с istreams как источник ввод данных через istream_iterator.
Я не мог понять жирный текст в приведенной выше цитате. Может ли кто-нибудь помочь мне понять это?
Кроме того, что означает следующий оператор (курсивный текст в приведенной выше цитате)? Как это связано с выражениями a==b
и ++a==++b
?
Равенство не гарантируют заменяющее имущество или реляционная прозрачность.
Ответы
Ответ 1
Указанные свойства:
Замещение Свойство
Для любых величин a и b и любого выражения F (x), если a = b, то F (a) = F (b) (если обе стороны имеют смысл, то есть хорошо сформированы).
Ссылочная прозрачность
Неформально это означает, что нет никакой разницы между значением и ссылкой на это значение (таким образом, как был введен термин).
В императивном программировании это сложная концепция, потому что мы используем для изменения наших переменных. Рик Хики (за Clojure) дает приятный разговор о различии между Identity и State, которые могут вам помочь. Суть его в том, что переменная является Identity. В любой момент времени Идентичность относится к государству. Государство никогда не меняется, однако идентификация может быть изменена для ссылки на другое государство.
Входные итераторы
Нарушение свойства замены является "очевидным" здесь, если мы определяем F(x)
в приведенном выше смысле как означающее ++x
, то мы имеем, что если итераторы ввода подтвердили свойство подстановки, следующее выражение будет a == b => ++a == ++b
.
Это неверно, потому что приращение итератора ввода может привести к аннулированию всех других итераторов ввода из того же источника. Из таблицы 107 в n3290 (стр. 831, чуть выше параграфа, который вы указали):
++ г
pre: r является разыменованным.
post: r является разыменованным или r проходит мимо конца.
post: любые копии предыдущего значения r больше не требуются, чтобы быть разыменованный или находящийся в домене ==.
То есть, когда мы выполняем ++a
, тогда b
может стать недействительным, и поэтому ++b
сам будет undefined.
Это прямое нарушение ++a == ++b
, поэтому свойство подстановки не выполняется.
Реляционная прозрачность здесь более очевидна. Если входные итераторы были ссылочно прозрачными, это означало бы, что они будут отличаться от значения, на которое они указывают. Ясно, что это не так, поскольку применение ++
не увеличивает значение, а итератор.
Ответ 2
Для входных итераторов приращение итератора делает недействительными копии одного и того же итератора.
Итак:
auto a = istream_iterator<whatever>(something);
auto b = a;
a == b; // true
++a; // b is now invalid
++b; // undefined behavior, I think, but in any case not guaranteed to
// result in anything sensible.
Так что, конечно, ++a == ++b
не гарантируется. То есть a == b
не означает ++a == ++b
.
Я думаю, что "свойство подстановки" означает "все, что вы делаете со значением a
, имеет тот же результат, что и то же, что и значение b
", или похожее - существуют различные варианты подстановки, может упоминаться, но что-то в этом роде. Я думаю, что в этом контексте это должно означать "позже делать то же самое с b
", так как если a == b
и я еще ничего не сделал, это не имеет значения, какой из a
и b
я они ссылаются на одну и ту же точку в потоке. Но когда я прирастаю, мне нужно выбрать одно, а другое - потерять, следовательно, трудность с ++a == ++b
.
"Ссылочная прозрачность" означает, что разные объекты являются независимыми, то есть они не являются ссылками/указателями или псевдонимами друг друга. В сочетании с "свойством замены" это означает:
В дальнейшем? Нет ранее или позже, поскольку операции не имеют глобальных побочных эффектов. Если вы не можете замените "позже", тогда вы не может заменить
Итераторы ввода в одной и той же последовательности обычно ссылаются на те же "фактические данные", что и файл-дескриптор или что-то еще, что само содержит изменчивое состояние. Поскольку a
и b
относятся к одному и тому же дескриптору файла, а их значение зависит от его состояния, у вас нет ссылочной прозрачности. Этот недостаток заключается в том, что замена не выполняется.
Итераторы пересылки, как правило, также ссылаются на одни и те же базовые данные (например, на контейнер), но пока вы используете их только для чтения (и не изменяете иным образом контейнер), они не предают этот факт, по крайней мере пока вы не начнете сравнивать адреса возвращаемых значений. Таким образом, они имеют ограниченный вид ссылочной прозрачности своей собственной ценности, что итераторы ввода этого не делают. Они все еще ссылаются на себя, поэтому все, что они называют, все еще псевдонимы.
Ответ 3
В объяснении говорится: "Они должны быть однопроходными алгоритмами".
Дело в том, что итератор во входном потоке представляет собой переходное состояние. После изменения итератора это состояние больше не существует; все остальные итераторы, представляющие это состояние, недействительны: после инкремента a
итератор b
становится недействительным.
Ответ 4
Итераторы ввода определяют последовательность, которая может быть прочитана только один раз; вход
хорошим примером может служить клавиатура или труба. Увеличение
istream_iterator
эффективно означает чтение далее в istream
,
извлечение символов, так что другие istream_iterator
в одном потоке
больше не будут действительны в отношении их положения. Представить
поток символов "abcdefg..."
(алфавит, в сумме), с двумя
istream_iterator<char>
, указывая на 'a'
. Увеличение одной из
они вызовут 'b'
для чтения из потока, и никакие другие
Итератор может когда-либо видеть это.
Ответ 5
Учтите, что входной итератор может быть подключен к потоку, считываемому с клавиатуры. Приращение итератора означает чтение следующего символа.
Также увеличение экземпляра итератора не означает прочтение одного и того же символа.