Fazit oben: Bei richtiger Behandlung von Leerzeichen kann Folgendes eof
verwendet werden (und sogar zuverlässiger sein als fail()
bei der Fehlerprüfung):
while( !(in>>std::ws).eof() ) {
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
( Vielen Dank an Tony D für den Vorschlag, die Antwort hervorzuheben. In seinem Kommentar unten finden Sie ein Beispiel dafür, warum dies robuster ist. )
Dem Hauptargument gegen die Verwendung eof()
scheint eine wichtige Subtilität über die Rolle des Leerraums zu fehlen. Mein Vorschlag ist, dass eof()
explizites Prüfen nicht nur nicht " immer falsch " ist - was in diesem und ähnlichen SO-Threads eine übergeordnete Meinung zu sein scheint -, sondern bei ordnungsgemäßem Umgang mit Leerraum auch für einen saubereren und zuverlässigeren Umgang sorgt Fehlerbehandlung und ist die immer richtige Lösung (obwohl nicht unbedingt die engste).
Um zusammenzufassen, was als "richtige" Kündigungs- und Lesereihenfolge vorgeschlagen wird, ist Folgendes:
int data;
while(in >> data) { /* ... */ }
// which is equivalent to
while( !(in >> data).fail() ) { /* ... */ }
Der Fehler aufgrund eines Leseversuchs über eof hinaus wird als Beendigungsbedingung angesehen. Dies bedeutet, dass es keine einfache Möglichkeit gibt, zwischen einem erfolgreichen Stream und einem Stream zu unterscheiden, der aus anderen Gründen als eof wirklich fehlschlägt. Nehmen Sie die folgenden Streams:
1 2 3 4 5<eof>
1 2 a 3 4 5<eof>
a<eof>
while(in>>data)
endet mit einem Satz failbit
für alle drei Eingänge. Im ersten und dritten eofbit
wird auch gesetzt. Nach der Schleife braucht man also eine sehr hässliche zusätzliche Logik, um einen richtigen Eingang (1.) von einem falschen (2. und 3.) zu unterscheiden.
Nehmen Sie Folgendes:
while( !in.eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
Hier wird in.fail()
überprüft, ob etwas zu lesen ist, es ist das richtige. Sein Zweck ist nicht nur ein While-Loop-Terminator.
So weit so gut, aber was passiert, wenn im Stream nachlaufender Speicherplatz vorhanden ist - was klingt nach der größten Sorge eof()
als Terminator?
Wir müssen unsere Fehlerbehandlung nicht aufgeben. iss einfach den Leerraum auf:
while( !in.eof() )
{
int data;
in >> data >> ws; // eat whitespace with std::ws
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
std::ws
Überspringt jeglichen potenziellen (null oder mehr) nachgestellten Speicherplatz im Stream, während das eofbit
und nicht das festgelegt wirdfailbit
. Funktioniert also in.fail()
wie erwartet, solange mindestens eine Daten gelesen werden muss. Wenn auch leere Streams akzeptabel sind, lautet die richtige Form:
while( !(in>>ws).eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
/* this will never fire if the eof is reached cleanly */
// now use data
}
Zusammenfassung: Eine ordnungsgemäß erstellte Konstruktion while(!eof)
ist nicht nur möglich und nicht falsch, sondern ermöglicht auch die Lokalisierung von Daten innerhalb des Gültigkeitsbereichs und bietet eine sauberere Trennung von Fehlerprüfung und Business as usual. Davon abgesehen, while(!fail)
ist inarguably ein häufige und terse Idiom und kann in einfachen (Einzeldaten pro Lesetyp) Szenarien bevorzugt sein.
scanf(...) != EOF
funktioniert auch in C nicht, dascanf
die Anzahl der erfolgreich analysierten und zugewiesenen Felder zurückgegeben wird. Die richtige Bedingung ist,scanf(...) < n
won
die Anzahl der Felder in der Formatzeichenfolge ist.