2010-12-01 28 views
16

Possible en double:
Why is iostream::eof inside a loop condition considered wrong?Test stream.good() ou stream.eof() lit la dernière ligne deux fois

je le morceau de code suivant:

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

Mais ceci lit deux fois la dernière ligne. Pourquoi cela arrive-t-il et comment puis-je le réparer?

Quelque chose se passe très similaire avec:

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

Comment est-ce un doublon? L'autre réponse ne mentionne même pas la boucle avec la fonction good() comme test. –

Répondre

30

Vous très, très rarement voulez vérifier mauvais, eof, et bon. En particulier pour eof (comme! Stream.eof() est une erreur courante), le flux en cours à EOF ne signifie pas nécessairement que la dernière opération d'entrée a échoué; inversement, ne pas être à EOF ne signifie pas que la dernière entrée a réussi. Toutes les fonctions d'état de flux - fail, bad, eof et good - vous indiquent l'état actuel du flux plutôt que de prédire le succès d'une opération future. Vérifiez le flux lui-même (ce qui équivaut à un inversé échec contrôle) après l'opération souhaitée:

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); 

Pour lire et traiter toutes les lignes:

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

Pointedly, bon() est mal nommé et n'est pas équivalent à tester le flux lui-même (ce que les exemples ci-dessus font).

+0

La partie concernant la vérification d'eof est correcte, mais la suggestion de vérifier le flux lui-même est un peu fausse. 'good()' signifie qu'aucun eofbit, badbit ou failbit n'est défini. 'fail()' signifie que badbit ou failbit est défini. La vérification du flux (soit en utilisant la conversion void *, soit l'opérateur!) Est exactement la même chose que d'appeler la fonction membre fail(). – KeithB

+2

@KeithB: Vous remarquerez peut-être que je suis sorti du groupe "devrait être rarement vérifié". Un flux échoué est ce qui est important, et la vérification du flux lui-même est presque toujours plus pratique que l'échec équivalent(). Comparez getline (flux, ligne) à! Getline (flux, ligne) .fail(). –

8

Il suffit d'utiliser

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

C'est la façon idiomatiques d'écrire une telle boucle. Je n'ai pas été en mesure de reproduire l'erreur (sur une machine Linux).

+0

Je viens juste de comprendre pourquoi cela fonctionne: Le dernier appel réussi à getline() _might_ set ** eof **, si la dernière ligne n'a pas de saut de ligne à la fin. Le bit ** fail ** est défini uniquement lorsqu'il y a un appel infructueux à getline(). Donc nous ne voulons pas terminer la boucle à ** eof **, mais nous voulons terminer à ** fail **. –

+0

Encore une chose .. Je faisais 'while (f.peek()! = EOF) {...}'. Je pense que c'est correct? Mais je vais utiliser votre réponse à l'avenir. –

1

Il n'a pas lu deux fois la dernière ligne mais parce qu'il a échoué à lire lorsqu'il a atteint eof, votre ligne de chaîne a la valeur qu'elle avait précédemment. C'est parce que f n'est plus "bon" quand il a lu EOF, pas quand il est sur le point de le lire.