Тестирование stream.good() или! Stream.eof() дважды читает последнюю строку

Возможный дубликат:
Почему iostream:: eof внутри условия цикла считается неправильным?

У меня есть следующий фрагмент кода:

ifstream f("x.txt");
string line;
while (f.good()) {
  getline(f, line);
  // Use line here.
}

Но это дважды читает последнюю строку. Почему это происходит и как его исправить?

Что-то очень похожее происходит с:

ifstream f("x.txt");
string line;
while (!f.eof()) {
  getline(f, line);
  // Use line here.
}

Ответ 1

Вы очень, очень редко хотите проверить плохое, эф и добро. В частности, для eof (as! Stream.eof() является распространенной ошибкой), поток, текущий в EOF, не обязательно означает, что последняя операция ввода не удалась; наоборот, не в EOF не означает, что последний вход был успешным.

Все функции состояния потока - fail, bad, eof и good - сообщают вам текущее состояние потока, а не прогнозируют успех будущей операции. Проверьте текущий поток (который эквивалентен проверке с инвертированным отказом) после желаемой операции:

if (getline(stream, line)) {
  use(line);
}
else {
  handle_error();
}

if (stream >> foo >> bar) {
  use(foo, bar);
}
else {
  handle_error();
}

if (!(stream >> foo)) {  // operator! is overloaded for streams
  throw SomeException();
}
use(foo);

Чтобы прочитать и обработать все строки:

for (std::string line; getline(stream, line);) {
  process(line);
}

Точно говоря, good() неверно назван и не эквивалентен тестированию самого потока (что видно из приведенных выше примеров).

Ответ 2

Просто используйте

ifstream f("x.txt");
while (getline(f, line)) {
    // whatever
}

Это идиоматический способ написать такой цикл. Я не смог воспроизвести ошибку (на машине Linux).

Ответ 3

Он не читал последнюю строку дважды, но поскольку она не читалась, когда она достигла уровня eof, ваша строка строки имеет значение, которое было ранее.

Это потому, что f больше не "хорош", когда он читал EOF, а не когда он собирается его прочитать.