Игнорирование EOF для std::cin в С++

У меня есть приложение, которое реализует интерактивную оболочку, похожую на то, как работает консоль Python/irb. Теперь проблема заключается в том, что если пользователь случайно нажимает ^D, выдается EOF, и мой вызов getline() возвращает пустую строку, которую я рассматриваю как «нет ввода» и снова отображаю подсказку.

Затем это приводит к бесконечному циклу, который печатает подсказку.

Теперь в Python я бы решил эту проблему, поймав EOFError, но в C++ не возникает никаких исключений, которые я мог бы поймать, и, похоже, в cin нет настройки для игнорирования EOF.

Любые подсказки?


person Armin Ronacher    schedule 23.03.2009    source источник


Ответы (5)


Если он ничего не может прочитать, он устанавливает failbit. Просто проверьте поток в условии if и очистите бит:

if(!getline(std::cin, myline)) {
    std::cin.clear();
    std::cout << "you should enter something" << std::endl;
}

Внутри последовательность в вашем случае такова:

  • Wait on the terminal for a string. Terminal will block until the user emits a newline. Two probable error cases possible
    1. User presses immediately EOF. This will make getline read nothing at all, and it will set the failbit and the eofbit.
    2. Пользователь что-то вводит, а затем нажимает EOF. Это заставит getline потреблять что-то, а затем он нажмет EOF при попытке получить следующий символ. Это приводит к установке eofbit.
  • Вы попытаетесь прочитать что-нибудь снова. Функция извлечения создаст объект типа istream::sentry, который проверяет, в каком состоянии находится поток. Если какой-либо из битов ошибки установлен, это приведет к немедленному возврату функции извлечения. Это вызвало бесконечный цикл раньше.

Вызов clear() очищает все биты ошибок, и вы можете снова продолжить чтение.

person Johannes Schaub - litb    schedule 23.03.2009

Правильное решение благодаря litb:

if (!getline(std::cin, str)) {
    std::cin.clear();
    std::cout << std::endl;
}
person Armin Ronacher    schedule 23.03.2009
comment
Пока не могу этого сделать. По неизвестным мне причинам я только что получил новую учетную запись, хотя я вошел в свою существующую :-/ - person Armin Ronacher; 23.03.2009
comment
@mitsuhiko Вероятно, вы вошли в систему, используя другую учетную запись openid. - person amit; 23.03.2009
comment
Вернул свой аккаунт. Похоже, что поддержка делегатов OpenID для stackoverflow немного глючит. - person Armin Ronacher; 23.03.2009

Функция getline() сообщает об ошибках, используя следующие биты:

  • eofbit
  • фейлбит
  • плохой бит

Попробуйте проверить их, прежде чем продолжить.

person dirkgently    schedule 23.03.2009
comment
Я могу их проверить, но я не могу игнорировать EOF таким образом. Поэтому я не могу продолжать использовать входной поток. Я мог только выйти из приложения, которое мне не нужно. - person Armin Ronacher; 23.03.2009
comment
черт, ты опередил меня на 1 минуту :) +1 - person Johannes Schaub - litb; 23.03.2009
comment
кстати, ссылка ведет на istream::getline. велика вероятность, что он использует std::getline ( cplusplus.com/reference/string/getline. html). - person Johannes Schaub - litb; 23.03.2009
comment
Мицухико, просто сделайте if(!getline(std::cin, myline)) { std::cin.clear(); std::cout ‹‹ веди себя, пожалуйста! ‹‹ стд::эндл; } - person Johannes Schaub - litb; 23.03.2009
comment
@litb: возможно. Я получаю пользу от сомнений ;-) - person dirkgently; 23.03.2009
comment
восстановленный ответ ниже, содержащий пример. - person Johannes Schaub - litb; 23.03.2009

См. http://www.horstmann.com/cpp/pitfalls.html.

Вы можете использовать такой код:

while (cin)
{  int x;
   cin >> x;
   if (cin) a.push_back(x);
}
person amit    schedule 23.03.2009
comment
@ypnos код должен был быть примером, а не решением. В любом случае, теперь у нас есть решение, благодаря Litb - person amit; 23.03.2009

Хорошо, в других ответах использование cin.clear() было описано как возможное решение.

Другой трюк заключается в том, что вы используете другие средства для обработки ввода с консоли, чем типичный стандарт, устанавливая терминал в другой режим, чтобы вы могли напрямую обрабатывать Ctrl + D. В режиме RAW или других вы получаете более прямой доступ к вводу, а управляющие последовательности со стороны пользователя (например, Ctrl+D или Ctrl+C) больше нигде не обрабатываются.

Некоторые библиотеки вы можете попытаться собрать больше информации (или даже сэкономить время кодирования):

½ Вы можете найти некоторую информацию о своей проблеме в документах здесь.

person ypnos    schedule 23.03.2009