Le top du top : En manipulant correctement les espaces blancs, voici comment procéder eof
peuvent être utilisées (et même, être plus fiables que les fail()
pour la vérification des erreurs) :
while( !(in>>std::ws).eof() ) {
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
( Merci Tony D pour la suggestion de mettre en évidence la réponse. Voir son commentaire ci-dessous pour un exemple expliquant pourquoi cela est plus robuste. )
Le principal argument contre l'utilisation eof()
semble manquer une subtilité importante sur le rôle de l'espace blanc. Ma proposition est que, en vérifiant eof()
toujours faux " - ce qui semble être l'opinion dominante dans ce fil de discussion et dans d'autres fils de discussion similaires sur les SO -, mais avec une gestion correcte des espaces blancs, il permet une gestion des erreurs plus propre et plus fiable, et il est l'outil de gestion des erreurs le plus efficace. toujours correct (bien qu'il ne s'agisse pas nécessairement de la solution la plus efficace).
En résumé, ce qui est suggéré comme étant l'ordre "correct" de terminaison et de lecture est le suivant :
int data;
while(in >> data) { /* ... */ }
// which is equivalent to
while( !(in >> data).fail() ) { /* ... */ }
L'échec dû à une tentative de lecture au-delà de eof est considéré comme la condition d'arrêt. Cela signifie qu'il n'y a pas de moyen facile de distinguer entre un flux réussi et un flux qui échoue réellement pour des raisons autres que eof. Prenons les flux suivants :
1 2 3 4 5<eof>
1 2 a 3 4 5<eof>
a<eof>
while(in>>data)
se termine par un ensemble failbit
para tous trois entrées. Dans le premier et le troisième, eofbit
est également fixé. Ainsi, au-delà de la boucle, il faut une logique supplémentaire très moche pour distinguer une entrée correcte (1ère) d'une entrée incorrecte (2ème et 3ème).
Attendu que, prenez ce qui suit :
while( !in.eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
Ici, in.fail()
vérifie que tant qu'il y a quelque chose à lire, c'est le bon. Son but n'est pas un simple terminateur de boucle while.
Jusqu'ici tout va bien, mais que se passe-t-il s'il y a un espace de queue dans le flux - ce qui semble être le problème majeur contre eof()
comme Terminator ?
Nous n'avons pas besoin de renoncer à notre gestion des erreurs ; il suffit de manger l'espace blanc :
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
saute tout espace de fin de ligne potentiel (zéro ou plus) dans le flux, tandis que le réglage de l'option eofbit
y pas le failbit
. Donc, in.fail()
fonctionne comme prévu, tant qu'il y a au moins une donnée à lire. Si les flux entièrement vides sont également acceptables, alors la forme correcte est :
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
}
Résumé : Une construction correcte while(!eof)
n'est pas seulement possible et n'est pas mauvaise, mais elle permet de localiser les données dans la portée et de séparer plus proprement la vérification des erreurs de l'activité habituelle. Ceci étant dit, while(!fail)
est incontestablement un idiome plus courant et plus concis, et peut être préféré dans des scénarios simples (du type données uniques par lecture).
27 votes
scanf(...) != EOF
ne fonctionnera pas non plus en C, carscanf
renvoie le nombre de champs analysés et attribués avec succès. La condition correcte estscanf(...) < n
donden
est le nombre de champs dans la chaîne de format.8 votes
@Ben Voigt, il retournera un nombre négatif (que EOF est généralement défini comme tel) au cas où EOF est atteint
23 votes
@SebastianGodelet : En fait, il retournera
EOF
si la fin du fichier est rencontrée avant la première conversion de champ (réussie ou non). Si la fin du fichier est atteinte entre deux champs, il renverra le nombre de champs convertis et stockés avec succès. Ce qui rend la comparaison avecEOF
mauvais.2 votes
@SebastianGodelet : Non, pas vraiment. Il se trompe quand il dit que "au-delà de la boucle, il n'y a pas de moyen (facile) de distinguer une entrée correcte d'une entrée incorrecte". En fait, c'est aussi simple que de vérifier
.eof()
après la sortie de la boucle.4 votes
@Ben Oui, pour ce cas (lecture d'un simple int). Mais on peut facilement imaginer un scénario où
while(fail)
La boucle se termine à la fois par un échec réel et par un eof. Pensez au cas où vous avez besoin de 3 entrées par itération (disons que vous lisez un point x-y-z ou quelque chose comme ça), mais qu'il n'y a, par erreur, que deux entrées dans le flux.1 votes
Cette question est analogue à la question C et a la même réponse : Pourquoi
while(!feof(file))
a toujours tort ? . Parce que l'indicateur n'est activé que après frappant l'EOF.0 votes
Voici le point de vue de C++ FAQ sur la même question.
0 votes
@sly : ce scénario de "3-ints" n'est pas correctement géré par
while (in >> x) { if (in >> y >> z) use(x, y, z); else FATAL("got an int not followed by 2 more!"); } if (!eof()) FATAL("didn't get integer where expected");
? Si non, pour quel contenu de flux cela no fonctionnent bien ?1 votes
Cette question a été postée sans attribution sur Quora : quora.com/unanswered/ (le titre de la question Quora correspond exactement au titre que cette question avait avant d'être modifiée hier).