ifstream und g++-Versionen



  • Folgender Code soll zweimal die selbe Datei ausgeben:

    #include <fstream>
    #include <iostream>
    
    int main()
    {
    	std::ifstream in;
    
    	in.open("test.txt");
    
    	while(!in.eof()) {
    		std::string str;
    		in >> str;
    		std::cout << str << std::endl;
    	}
    
    	in.close();
    
    	in.open("test.txt");
    
    	std::cout << std::endl << std::endl;
    
    	while(!in.eof()) {
    		std::string str;
    		in >> str;
    		std::cout << str << std::endl;
    	}	
    
       in.close();
    
    	return 0;
    }
    

    Mit dem g++ 4.2.1 unter Linux tut das Program auch, was es soll. Mit dem g++ 3.3.3 gibt es die Datei aber nur einmal aus - nach dem ersten close() und dem zweiten open() wird anscheinend der Dateipointer nicht wieder auf den Anfang zurück gestellt.

    Warum verhalten sich die beiden Compiler unterschiedlich? Oder ist an dem Code irgendetwas undefiniert?



  • Bei mir läuft es auch unter Windows.

    Ich weiß nicht genau, aber vll machst du mal nach der ersten Schleife ein in.clear()

    Lg freeG



  • fr33g schrieb:

    Bei mir läuft es auch unter Windows.

    Ich weiß nicht genau, aber vll machst du mal nach der ersten Schleife ein in.clear()

    Lg freeG

    Danke für den Hinweis, aber mir gehts gar nicht darum, wie man das löst. Da fallen mir genug Möglichkeiten ein. Ich hab nur einen halben Tag gebraucht, um dieses Problem in meinem Programm zu finden. Und nu will ich gerne wissen, *warum* der g++ 3.3.3 anders geht als der g++ 4.2.1 oder dein Windows-Compiler.



  • Meiner Meinung nach ist der Code korrekt, du prüfst allerdings nicht auf Fehler. Möglicherweise setzt der gcc 3 das fail-Bit beim close.

    Grundsätzlich können in diesem Uraltcompiler natürlich eine Menge Fehler stecken. Ich würde da etwas neueres bevorzugen.



  • Der Standard definiert nicht, dass std::basic_ifstream::open irgendwelche Flags zu bereinigen hätte, also verhält sich gcc 3.3.3 hier streng genommen durchaus korrekt. Ich vermute, dass das in späteren Compilerversionen geändert wurde, weil es intuitiv mehr Sinn macht und es von anderen Compilern üblicherweise so gemacht wird.



  • Aso ok, also ich habe es mim MinGW unter Windows getestet.
    Ich könnte mir vorstellen, dass der eine vll bei ifstream.close() die Fehlerbits löscht und der Andere eben nicht. Wobei es eigentlich laut Standard richtig ist die Fehlerbits bei close nicht zu löschen.

    Lg freeG

    EDIT: Und wieder mal 9 Sekunden zu langsam 😃



  • OK, danke.



  • Der Code ist mehrdeutig und das Ergebnis ist auch noch vom Inhalt der Datei abhängig. Obwohl ich annehme, dass Mups jedes mal die selbe Datei verwendet hat.

    Zunächst mal finde ich es mindestens schlechten Stil, ein fstream-Objekt nach close wieder zu verwenden. Da können vorher sonst was für Einstellungen an dem Stream vorgenommen werden und diese bleiben alle nach close erhalten.

    Ein eindeutiger Fehler ist diese leidige while(!EOF)-read-Schleife. Dabei muss es sich um eine Art Virus von der hartnäckigsten Sorte handeln. Eine andere Erklärung fällt mir dazu nicht ein.

    Falls beim Einlesen eines Strings ein Fehler auftritt (ok, ok - ich weiß es passiert genau hier eigentlich nie!), dann landet man in einer Endlosschleife, da der Stream zwar in den Zustand Fail, aber nicht EOF geht. Ist das letzte Zeichen kein Whitespace so läuft die Schleife so ab, wie man es sich wünscht, ist es aber ein Whitespace (z.B. LF), dann geht der Stream nach EOF und nach Fail. Was der letzte String enthält, ist von der Implementierung von istream>>string abhängig, da dies bei Fail undefiniert ist.
    Das macht auch den Unterschied aus, wenn man den Stream anschließend wieder öffnet ...

    Korrekt wäre etwa:

    #include <fstream>
    #include <iostream>
    
    int main()
    {
        {
            std::ifstream in("test.txt");
            for( std::string str; in >> str; )
                std::cout << str << std::endl;
        }
        {
            std::ifstream in("test.txt");
            for( std::string str; in >> str; )
                std::cout << str << std::endl;
        }
        return 0;
    }
    

    ich würde darauf wetten, dass sich obiger Code auf beiden Compilern gleich verhält.

    Gruß
    Werner



  • Oder einfach auf good() checken.



  • Ethon schrieb:

    Oder einfach auf good() checken.

    Ja aber ist doch unnötig, dann haste noch ne Zeile mehr, so reicht es doch vollkommen, da ja in >> str geprüft wird und wenn was schief geht, ist die Schleife vorbei.

    Lg freeG


Anmelden zum Antworten