2010-03-02 4 views
4

je jouais avec itérateurs IStream et la gestion des exceptions, il y a quelques jours et je suis tombé sur cette curiousity:flux d'entrée itérateurs et les exceptions

#include <iostream> 
#include <fstream> 
#include <iterator> 
#include <algorithm> 

using namespace std; 

int main(int argc, char* argv[]) 
{ 
    if (argc < 2) { 
     cout << argv[0] << " <file>" << endl; 
     return -1; 
    } 

    try { 
     ifstream ifs(argv[1]); 
     ifs.exceptions(ios::failbit | ios::badbit); 
     istream_iterator<string> iss(ifs), iss_end; 
     copy(iss, iss_end, ostream_iterator<string>(cout, "\n")); 
    } 
    catch (const ios_base::failure& e) { 
     cerr << e.what() << endl; 
     return -2; 
    } 

    return 0; 
} 

Pourquoi une exception failbit est toujours élevé après avoir lu le dernier mot le fichier d'entrée?

+0

Pourrait-on corriger le formatage, s'il vous plaît? –

+0

Je n'ai jamais lu de fichier avec des itérateurs quand j'étais programmin en C++ mais en cycle de lecture standard j'avais une condition spéciale pour la fin du fichier (ie lire sans EOF) – Roman

+1

@Roman: alors vous avez fait mal. Seul le test de EOF aboutira à une boucle infinie en cas d'erreur de lecture car la fin du fichier ne sera jamais atteinte. Il est recommandé de toujours tester ** both ** pour EOF et l'échec. D'autre part, le code OP utilise des exceptions, donc il est sûr. –

Répondre

0

On détecte la condition EOF en lisant jusqu'à une défaillance - qui déclenche l'exception - puis en vérifiant la cause de l'échec.

Pour développer: l'istream_iterator devient invalide lorsque, après avoir lu une valeur avec >>, l'opérateur de flux void * renvoie NULL. Mais pour cela, l'opérateur >> doit définir le bit d'échec, donc augmenter l'exception.

0

Bonne question. Ce serait bien d'être capable d'attraper d'autres échecs dans cet appel, mais de le faire continuer normalement quand il frappe l'eof. Cela dit, je n'ai pas utilisé d'exceptions avec les flux avant. Je pense que vous pourriez faire la copie et vérifier l'état du cours d'eau après pour détecter d'autres erreurs, par exemple:

ifstream ifs(argv[1]); 
if (!ifs) { 
    cerr << "Couldn't open " << argv[1] << '\n'; 
    return -1; 
} 
//ifs.exceptions(ios::failbit | ios::badbit); 
istream_iterator<std::string> iss(ifs), iss_end; 
copy(iss, iss_end, ostream_iterator<std::string>(cout, "\n")); 
if (!ifs.eof()) { 
    cerr << "Failed to read the entire file.\n"; 
    return -2; 
} 
+0

@Roman: Je ne peux pas tester moi-même la condition de fin de fichier dans ce programme car je n'ai pas le contrôle de la boucle de lecture. C'est l'algorithme "copie" qui doit le tester. Quoi qu'il en soit, le constructeur par défaut de istream_iterator crée un itérateur "passé la fin" (en utilisant la terminologie STL), qui est dans ce cas EOF, pour terminer la boucle (second argument de "copy"). –

+0

@AProgrammer: mais c'est l'astuce du programme (et la raison de ma question). Je n'ai pas spécifié ios :: eofbit dans ifs.exceptions (...), donc "copier" devrait normalement atteindre la fin du fichier et ne déclencher aucune exception. Je veux dire, ce que vous dites serait correct si je l'avais fait comme ceci: ifs.exceptions (ios :: failbit | ios :: badbit | ios :: eofbit). –

+0

Vous semblez avoir mis des commentaires à un mauvais poste :) Mais je pense que la fin vient pour istream_iterator quand il échoue, pas à l'eof. En outre, il semble que ces conditions ne puissent pas être testées de manière fiable séparément. Par exemple, ajoutez un espace à "foo" dans la réponse de coppro, et vous trouverez que eofbit et failbit sont définis en même temps. Donc soit vous n'utilisez pas d'exceptions, soit vous acceptez que EOF est exceptionnel ... – UncleBens

3

failbit est réglé chaque fois qu'une opération de lecture n'extraire tous les caractères, que ce soit parce qu'il a frappé EOF ou pas.

stringstream ss ("foo"); 
string s; 
int i; 

ss >> i; // sets failbit because there is no number in the stream 
ss.clear(); 
ss >> s; // sets eofbit because EOF is hit 
ss.clear(); 
ss >> s; // sets eofbit and failbit because EOF is hit and nothing is extracted.