iostream: stream states



  • Hi,
    ich beschäftige mich momentan näher mit Streams und es gibt einige Sachen die ich nicht verstehe und mir Kopfschmerzen bereiten.

    z.B.:
    Ich möchte ein Config File mit 5 Zeilen einlesen und mein Code dazu sieht so aus:

    bool Foo::load_config(){
    
        ifstream input(".\\filepaths.txt");
    
        if (!input.is_open())
            return false;
    
        string tmp;
        tmp.reserve(40);
    
        while (input >> tmp){
    //        cout << input.rdstate() << endl;
            filepaths.emplace_back(tmp);
    
        }
    
        if (input.rdstate() == ios_base::eofbit)
            return true;
        else return false;
    
    }
    

    Soweit ich das bis jetzt verstanden habe bricht die While-Schleife ab sobald etwas schiefgeht oder eof erreicht ist
    Der Status des Streams kann mit .rdstate() abgefragt werden.

    1. Der rdstate() des Streams ist während der ersten 4 Durchläufe der While-Schleife "0". Beim 5 Durchlauf (letzte Zeile) wird der rdstate() des Streams auf eofbit gesetzt.

    1. Frage: Wie kann er während er die letzte Zeile liest schon wissen, dass danach nichts mehr kommt? Gibt es hinter dem letzten Buchstaben einer Textdatei ein "hier ist Ende" Zeichen? Ich finde es irgendwie merkwürdig, dass er den Stream-state auf eofbit setzt und dann noch einmal durch die Schleife rennt.

    2. Der rdstate() des Streams wird nachdem er die Schleife verlässt von Eofbit(1) auf "3" geändert. Ich habe leider nicht rausgefunden was 3 ist.
    Weiß das jemand?

    Goodbit = 0
    Eofbit = 1
    Failbit = 2
    Badbit = 4

    Warum ich das so genau Frage:
    Ich möchte, dass die bool load_config(); Funktion false zurückgibt in Folgenden Fällen.
    1. Datei konnte nicht geöffnet werden
    2. Failbit wurde gesetzt
    3. Badbit wurde gesetzt.

    Mein Weg dies zu tun war unter der While-Schleife den rdstate des Streams abzufragen und bei ios_base::eofbit "True" zurückzugeben und ansonsten "False".

    Wie weiter oben geschrieben ist der rdstate des Streams aber 3 und nicht 1.
    Weiß jemand, wie ich mein Ziel trotzdem erreichen kann oder kann mir dieses Verhalten erklären?



  • 1+2=3
    Das Fail- und das Eofbit sind gesetzt. Wenn deine Datei am Ende keinen Zeilenumbruch hat, wird bis zum Dateiende gelesen, deshalb ist EOF schon gefunden.



  • manni66 schrieb:

    1+2=3
    Das Fail- und das Eofbit sind gesetzt. Wenn deine Datei am Ende keinen Zeilenumbruch hat, wird bis zum Dateiende gelesen, deshalb ist EOF schon gefunden.

    o_O
    Er addiert die States?
    Wenn nach eofbit ein badbit kommt ist der State dann 5 ?
    Wie baut man denn dann solide Abfragen?

    Das bedeutet doch eigentlich, wenn ich es korrekt haben will müsste die letzte Operation in der while-Schleife ein if eofbit break sein.
    Damit es beim nächsten Read nicht zu einem logischen I/O Error kommt.

    Wobei ich die if-Abfrage in der Schleife schon irgendwie ziemlich häßlich finde.

    bool Foo::load_config(){
    
        ifstream input(".\\filepaths.txt");
    
        if (!input.is_open())
            return false;
    
        string tmp;
        tmp.reserve(40);
    
        while (input >> tmp){
    //        cout << input.rdstate() << endl;
            filepaths.emplace_back(tmp);
    
            if (input.rdstate() == ios_base::eofbit)
                break;
        }
    
        if (input.rdstate() == ios_base::eofbit)
            return true;
        else return false;
    
    }
    


  • Es sind, wie der Name schon sagt, Bits. Da können halt auch mehrere gesetzt sein. Der stream hat aber auch Funktionen (eof, fail, ...) um sie abzufragen. Die if-Abfrage ist nicht notwendig, benutze einfach die eof Funktion für das return.



  • manni66 schrieb:

    Es sind, wie der Name schon sagt, Bits. Da können halt auch mehrere gesetzt sein. Der stream hat aber auch Funktionen (eof, fail, ...) um sie abzufragen. Die if-Abfrage ist nicht notwendig, benutze einfach die eof Funktion für das return.

    Danke, das funktioniert, allerdings irritiert mich nur irgendwie das Konzept dahinter.

    Ich meine das bedeutet, dass bei jeder I/O Streamoperation am Ende ein logischer I/O Error (failbit) kommt.

    Kann denn ein logischer I/O Error(failbit) auch an einer anderen Stelle geschehen, als bei der letzten read Operation oder ist der logische I/O Error eigentlich gleichbedeutend mit eof?



  • Fail passiert immer, wenn man versucht etwas zu lesen, was nicht da ist:

    #include <string>
    #include <sstream>
    #include <iostream>
    
    void print_state( std::istream const & is )
    {
    	if( is.eof() )
    		std::cout << "eof ";
    	if( is.fail() )
    		std::cout << "fail ";
    	if( is.bad() )
    		std::cout << "bad ";
    	if( is.good() )
    		std::cout << "good";
    
    	std::cout.put( '\n' );
    }
    
    int main()
    {
    	std::stringstream ss{ "foo 42 bar" };
    
    	std::string str;
    	unsigned number;
    
    	// vielleicht eine Zahl lesen?
    	ss >> number;
    	print_state( ss ); // -> fail
    	ss.clear();
    
    	// Nein? Dann halt einen String
    	ss >> str;
    	print_state( ss ); // -> good	
    
    	// jetzt vielleicht eine Zahl?
    	ss >> number;
    	print_state( ss ); // -> good
    
    	// noch eine?
    	ss >> number;
    	print_state( ss ); // -> fail. Njet.
    	ss.clear();
    
    	// Dann halt einen String
    	ss >> str;
    	print_state( ss ); // -> jep, kein fail. aber eof -> es kommt nichts mehr.
    }
    


  • Swordfish schrieb:

    void print_state( std::istream const & is )
    {
    	if( is.eof() )
    		std::cout << "eof ";
    	if( is.fail() )
    		std::cout << "fail ";
    	if( is.bad() )
    		std::cout << "bad ";
    	if( is.good() )
    		std::cout << "good";
    
    	std::cout.put( '\n' );
    }
    

    Gute Funktion. Könnte in die FAQ rein.



  • Ruvi schrieb:

    manni66 schrieb:

    1+2=3
    Das Fail- und das Eofbit sind gesetzt. Wenn deine Datei am Ende keinen Zeilenumbruch hat, wird bis zum Dateiende gelesen, deshalb ist EOF schon gefunden.

    o_O
    Er addiert die States?
    Wenn nach eofbit ein badbit kommt ist der State dann 5 ?
    Wie baut man denn dann solide Abfragen?

    Nein, er verodert die einzelnen States. Und das ist auch der Grund warum das nur die Zweierpotenzen sind. Zufällig sieht dann die Oder-Operation so aus wie ein Plus.

    Und du kannst dir die einzelnen States mit einem Und wieder da raus holen:

    enum {
    	GOOD = 0,
    	EOF = 1,
    	FAIL = 2,
    	BAD = 4
    };
    
    int flags = EOF | BAD;
    
    if ( flags == GOOD )
    {
    }
    else
    {
    	if ( flags & EOF == EOF )
    	{}
    	if ( flags & FAIL == FAIL )
    	{}
    	if ( flags & BAD == BAD )
    	{}
    }
    

  • Mod

    Gute Funktion. Könnte in die FAQ rein.

    Wie wäre es mit

    #include <iostream>
    
    std::ios& print_state( std::ios& is )
    {
    	std::ostream& out = (&is == &std::cout? std::clog : std::cout); // Falls cout das failbit gesetzt hat
    	if (is.good())
    		out << "good";
    	else
    	{
    		if (is.bad())
    			out << "*bad* ";
    		if (is.eof())
    			out << "eof ";
    		if (is.fail())
    			out << "fail ";
    	}
    
    	out << '\n';
    	return is;
    }
    
    int main()
    {
    	std::cout << print_state;
    	std::cin >> print_state;
    }
    


  • Arcoth schrieb:

    std::cin >> print_state;
    

    Semkantik daneben!?



  • Arcoth schrieb:

    std::ios& print_state( std::ios& is )
    

    Super nützlicher Rückgabewert!

    Arcoth schrieb:

    std::ostream& out = (&is == &std::cout? std::clog : std::cout); // Falls cout das failbit gesetzt hat
    

    100% POLA-konform!

    Arcoth schrieb:

    out << "*bad* ";
    

    *bad* bedarf ganz sicher besondere Aufmerksamkeit.

    Die Leerzeichen sind sicher auch sehr nützlich vor dem Linebreak

    Arcoth schrieb:

    out << '\n';
    

    der in jede unscheinbare Ausgabefunktion hineingehört.

    Arcoth schrieb:

    std::cout << print_state << '\n';
    

    Compile error. Aha, deshalb das '\n' . POLA ftw.

    Arcoth schrieb:

    std::cin >> print_state;
    

    Ok, ich gebs auf. Da läuft was ganz grundsätzlich schief.



  • Wundert mich eh, daß es ohne template vonstatten ging.



  • thedailywtf schrieb:

    Arcoth schrieb:

    std::cout << print_state << '\n';
    

    Compile error. Aha, deshalb das '\n' . POLA ftw.

    Eigentlich kein Comile error. Höchstens, wenn Du den komischen Rückgabetyp geändert hättest.


  • Mod

    thedailywtf schrieb:

    *bad* bedarf ganz sicher besondere Aufmerksamkeit.

    Ja, warum nicht? Deutet schließlich auf einen irreparablen Fehler hin und sollte entsprechend gekennzeichnet werden.

    thedailywtf schrieb:

    Die Leerzeichen sind sicher auch sehr nützlich vor dem Linebreak

    Nein, aber es ist ganz nützlich zwischen Wörtern. "eoffail" wäre nicht so lesbar, weißt du.
    Falls du dich allerdings auf das eine Leerzeichen in "fail " aufregst, muss ich dir sowohl zu deinen Adleraugen als auch zu deinem Scharfsinn gratulieren.

    thedailywtf schrieb:

    der in jede unscheinbare Ausgabefunktion hineingehört.

    Komisch - bei Swordfish's Variante hast du dich nicht beschwert. Diesen Einwand hast du aber vorausgesehen und das Wörtchen unscheinbar eingebaut. Ich muss dir abermals zu deinem Scharfsinn gratulieren!

    thedailywtf schrieb:

    Compile error

    Die Signatur der aufgerufenen Operatorfunktion ist übrigens

    basic_ostream& operator<<( std::basic_ios<CharT,Traits>& (*func)(std::basic_ios<CharT,Traits>&) );
    

    Zitieren musst du auch noch lernen.



  • Wenn man es mehr "fancy" haben will...

    Könnte man nen Wrapper für std::ios_base::iostate machen und für diesen dann nen Stream-Insertion-Operator definieren.

    Oder der Swordfish Variante nen zusätzlichen Output-Stream Parameter verpassen der zum Output verwendet wird.

    Arcoth schrieb:

    thedailywtf schrieb:

    der in jede unscheinbare Ausgabefunktion hineingehört.

    Komisch - bei Swordfish's Variante hast du dich nicht beschwert. Diesen Einwand hast du aber vorausgesehen und das Wörtchen unscheinbar eingebaut. Ich muss dir abermals zu deinem Scharfsinn gratulieren!

    Swordfish's Variante ist eine benannte Funktion. Bei benannten Funktionen kommt es schonmal vor dass die nen "\n" rausschreiben.
    Bei einem Stream-Operator bzw. -Manipulator erwartet man es aber eher nicht.
    Wobei die eigentliche POLA Verletzung mMn. die ist dass ein Stream-Manipulator nicht "seinen" Stream manipuliert sondern stattdessen auf einem anderen Stream etwas ausgibt.



  • Ihr habt doch alle einen an der Waffel.



  • Kellerautomat schrieb:

    Ihr habt doch alle einen an der Waffel.

    Ach quatsch, wir sind nur gründlich.

    hustbaer schrieb:

    Bei benannten Funktionen kommt es schonmal vor dass die nen "\n" rausschreiben.

    Gemeint war natürlich '\n'. 💡



  • volkard schrieb:

    hustbaer schrieb:

    Bei benannten Funktionen kommt es schonmal vor dass die nen "\n" rausschreiben.

    Gemeint war natürlich '\n'. 💡

    Verstehe ich nicht.
    Was ist da der (relevante) Unterschied?



  • hustbaer schrieb:

    volkard schrieb:

    Gemeint war natürlich '\n'. 💡

    Was ist da der (relevante) Unterschied?

    Vergiss es. Volkard will mich bloß verarschen.


Anmelden zum Antworten