Каков результат увеличения istream_iterator, который уже находится в конце потока?
Я посмотрел на стандарт и не увидел очевидного ответа.
Предположим, я сделал это:
std::istream_iterator<char> is(file);
while(is != std::istream_iterator<char>()) {
++is;
}
сейчас is
находится в конце потока и равен std::istream_iterator<char>()
, Что произойдет, если я увеличу его еще раз? Это все еще равно std::istream_iterator<char>()
? или результат не определен?
Стандарт прямо заявляет, что *is
неопределенное поведение, если is
находится в конце потока. Но я ничего не видел относительно итерации за пределами конца потока...
РЕДАКТИРОВАТЬ:
Я спрашиваю, потому что я наткнулся на некоторый код, который делает что-то вроде этого:
// skip 2 input chars
++is;
++is;
if(is != std::istream_iterator<char>()) {
// continue using is and do some work...but what if the first
// increment made it EOS? is this check valid?
}
2 ответа
Таблица 72 в C++03 о требованиях итератора ввода говорит, что предварительное условие ++r
в том, что r
де-ссылочный. Те же условия выполняются для r++
,
Сейчас, 24.5.1/1
говорит о istream_iterator
Результат
operator*
на конце потока не определяется.
В заключение, последствия operator++
в конце потока итератор не определен.
Таблица 72 в C++03 о требованиях итератора ввода говорит, что предварительное условие ++r
в том, что r
де-ссылочный. Те же условия выполняются для r++
,
Сейчас, 24.5.1/1
говорит о istream_iterator
Результат
operator*
на конце потока не определяется.
В заключение, последствия operator++
в конце потока итератор не определен.
Обратите внимание, что я считаю, что этот вывод делает поведение неопределенным только тогда, когда вы пишете или используете алгоритм, принимающий входные итераторы, которые демонстрируют такое поведение, а затем передаете итератор istream. Начиная с использования только самого итератора istream, не рассматривая его как входной итератор и полагаясь на его инварианты, я думаю, что приведенный выше вывод не совсем верен (у нас может быть класс, который не требует r
разыменовывается, например).
Но, глядя на то, как описан итератор istream, вызов operator++
после достижения конца значения потока приводит к неопределенному поведению либо. operator==
ибо это определяется как эквивалент
x.in_stream == y.in_stream
куда in_stream
является указателем на поток, перебранный - и представленный в стандартном тексте для определения поведения и семантики "только экспозиция". Теперь единственная реализация, о которой я могу думать, которая делает эту работу, использует итератор конца потока, который хранит в качестве указателя потока нулевой указатель. Но operator++
определяется как делать что-то, имеющее эффект следующего
*in_stream >>value
Теперь, если вы войдете в состояние конца потока, и мы установим in_stream
к нулевому указателю, тогда, конечно, эффект этого будет неопределенным поведением.
Таким образом, даже если вы используете только итератор istream, нет никаких гарантий, что вы можете увеличивать значение после конца потока.
Если он не определен, он не определен:-) В стандартных (последний черновик C++0X) словах мой акцент:
неопределенное поведение
поведение, которое может возникнуть при использовании ошибочной программной конструкции или ошибочных данных, к которым настоящий международный стандарт не предъявляет никаких требований. Неопределенное поведение может также ожидаться, когда в этом международном стандарте опущено описание любого явного определения поведения.