Есть ли какие-либо гарантии при unget?

#c

#c

Вопрос:

Учитывая следующее:

 char c;
cin >> c;
cin.unget();
  

Предполагая, что ввод символа был успешным, гарантированно ли unget сможет создать резервную копию хотя бы этого одного символа? Если я запрошу и успешно получу строку, можно ли гарантировать, что мне будет разрешено вызывать unget вплоть до начала этой строки?

Ответ №1:

Вы гарантированно сможете unget использовать хотя бы 1 символ. Больше одного зависит от реализации и обстоятельств, поэтому вам не следует предполагать, что вы можете unget больше одного.

РЕДАКТИРОВАТЬ: Извините, я думал о libc int unget(int ch, FILE *stream) . Что говорится в стандарте:

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

Я посмотрю, смогу ли я найти именно то, что сказано о basic_istream<>amp; unget()

РЕДАКТИРОВАТЬ: Хорошо, итак, вот что говорится о стандарте c basic_istream<>amp; unget() (выделено мной жирным шрифтом):

Ведет себя как неформатированная функция ввода (как описано в 27.6.1.3, параграф 1). После построения sentry объекта, !good() вызовы setstate(failbit) if, которые могут вызвать исключение, и возврат. Если rdbuf() не равно null, вызывает rdbuf()->sungetc() . Если rdbuf() равно null, или если sungetc() возвращает traits::eof() , вызывает setstate(badbit) (который может выдать ios_base::failure ошибку (27.4.4.3)).

Итак, важным моментом является то, что он вызывает sungetc() , поэтому давайте посмотрим, что говорит об этом стандарт:

Если позиция возврата входной последовательности недоступна, возвращается pbackfail() . В противном случае уменьшает следующий указатель для входной последовательности и возвращает traits::to_int_type(*gptr()) .

Я не вижу ничего, что явно указывало бы на ограничение, так что стоит попробовать. Если я правильно понимаю, это скорректирует указатели в буфере резервного потока. Таким образом, пока в буфере достаточно «истории», он должен продолжать работать успешно.

Однако, в отличие от C, кажется, что вам никогда не гарантируется, что это сработает, но вы, вероятно, сможете вернуть более одного символа.

Итак, мой совет — не зависеть от ввода более одного символа и всегда проверять наличие сбоя.

Комментарии:

1. Если вы посмотрите на требования к реализации, uflow() и underflow() вы можете сделать вывод, что если streambuf когда-либо предоставлял символ, то в буфере возврата всегда будет хотя бы один символ. uflow() всегда переносит один символ из ожидающей последовательности в резервную последовательность, что подразумевает, что после любого успешного выполнения резервного копирования должно быть по крайней мере на один символ sbumpc() . (Если вы сделали только sgetc() , это действительно «беглый просмотр», поэтому у вас может не быть места для возврата.)

Ответ №2:

Вам следует рассмотреть возможность использования std::istream::peek вместо этого.

Это позволяет вам проверять следующий доступный символ, фактически не извлекая его из потока. Таким образом, вам не придется возвращать его обратно 🙂