Was ist der wahre Grund, das EOF-Bit nicht als unsere Stream-Extraktionsbedingung zu verwenden?

Inspiriert von meinemvorherige Frage

Ein häufiger Fehler für neue C ++ - Programmierer besteht darin, aus einer Datei etwas zu lesen, das ungefähr so ​​lautet:

std::ifstream file("foo.txt");
std::string line;
while (!file.eof()) {
  file >> line;
  // Do something with line
}

Sie berichten oft, dass die letzte Zeile der Datei zweimal gelesen wurde. Die allgemeine Erklärung für dieses Problem (eine, die ich zuvor gegeben habe) lautet wie folgt:

Die Extraktion setzt das EOF-Bit im Stream nur, wenn Sie versuchen, das Dateiende zu extrahieren, nicht, wenn Ihre Extraktion nur am Dateiende endet.file.eof() wird Ihnen nur sagen, ob der vorherige Lesevorgang das Dateiende erreicht hat und nicht, ob der nächste dies tut. Nachdem die letzte Zeile extrahiert wurde, ist das EOF-Bit immer noch nicht gesetzt und die Iteration wird noch einmal durchgeführt. Bei dieser letzten Iteration schlägt die Extraktion jedoch fehl undline hat immer noch den gleichen Inhalt wie zuvor, d. h. die letzte Zeile wird dupliziert.

Der erste Satz dieser Erklärung ist jedoch falsch, und daher ist auch die Erklärung, was der Code tut, falsch.

Die Definition formatierter Eingabefunktionen (dieoperator>>(std::string&) is) definiert Extraktion als usingrdbuf()->sbumpc() oderrdbuf()->sgetc() Eingabezeichen zu erhalten. Es besagt, dass, wenn eine dieser Funktionen zurückgibttraits::eof(), dann wird das EOF-Bit gesetzt:

Obrdbuf()->sbumpc() oderrdbuf()->sgetc() kehrt zurücktraits::eof()Wenn dies nicht ausdrücklich anders angegeben ist, führt die Eingabefunktion ihre Aktionen aus und führt sie aussetstate(eofbit), die werfen könnenios_base::failure (27.5.5.4) vor der Rückkehr.

Wir können dies an dem einfachen Beispiel sehen, das a verwendetstd::stringstream anstatt einer Datei (beide sind Eingabestreams und verhalten sich beim Extrahieren gleich):

int main(int argc, const char* argv[])
{
  std::stringstream ss("hello");
  std::string result;
  ss >> result;
  std::cout << ss.eof() << std::endl; // Outputs 1
  return 0;
}

Hier ist klar, dass die einzelne Extraktion erhalten wirdhello von der Schnurund setzt das EOF-Bit auf 1.

Was stimmt also nicht mit der Erklärung? Was ist anders an Dateien, die dazu führen!file.eof() wird die letzte Zeile dupliziert? Was ist der wahre Grund, warum wir nicht verwenden sollten!file.eof() als unsere Extraktionsbedingung?

Antworten auf die Frage(2)

Ihre Antwort auf die Frage