try/catch in do/while = endlosschleife?



  • Hi, wir fangen bei uns an der Uni gerade mit c++ an, und sollen ein kleines Konsolen Programm schreiben, das u.A. exception-handling benutzt...

    Für eine Menüsteuerung dachte ich mir daher, man könne einfach per try-catch Fehleingaben abfangen. Ich benutze zum einlesen den std::cin Befehl. Wird allerdings eine Exception geworfen, so wiederholt sich zwar die do-while schleife, der cin Befehl wird aber übersprungen...

    Hier mein Programmcode:

    int auswahl;
    bool eingabe_ok = false;
    
    cout << "\n +++++ " << getName() << ": Wähle eine Funktion:";
    
    // Erwartet wird die Eingabe "1" oder "2"
    
    do{
    cout << "\n +++++ Triff deine Auswahl: ";
    try{
    cin >> auswahl;
    if(auswahl == 1 || auswahl == 2) eingabe_ok = true;
    else cout << "\n +++++ Bitte korrigieren Sie Ihre Eingabe.";
    }catch(...){
    cout << "\n +++++ Bitte korrigiere deine Eingabe.";
    }
    }while(eingabe_ok == false);
    

    Gibt man nun was anderes als 1 oder 2 ein (bla, blubb, foo, alles was halt ein String ist), so kommt ununterbrochen die Ausgabe:

    +++++ Triff deine Auswahl:
    +++++ Bitte korrigiere deine Eingabe.
    +++++ Triff deine Auswahl:
    +++++ Bitte korrigiere deine Eingabe.
    +++++ Triff deine Auswahl:
    +++++ Bitte korrigiere deine Eingabe.
    +++++ Triff deine Auswahl:
    +++++ Bitte korrigiere deine Eingabe.

    Wenn es am cin Befehl liegt, könnte mir dann jemand den korrigierten Code geben?



  • so benutzt du try/catch auch völlig falsch

    so benutzt man es richtig

    int foo(int a)  throw char*    //muss man aber nicht schreiben, mehr dazu unten
    {
        if ( a == 0 )
           throw "Fehler";
        else
           return a*a*a;
    }
    
    int main()
    {
        int i;
        cin >> i;
        try {
          foo(i);
        catch(const char* a);
        cout << a << endl;
    }
    

    das throw (oder wars throws??) ist nicht nötig, man kennzeichnet so nur in der funktions deklaration dass eine exceptions geworfen werden kann
    schriebt man nichts hin kann alles passieren, schreibt man throw "Datentyp" dahin wird eine exception von genau diesen typ geworfen (in dem beispiel ein char* string), lässt man die klammern bei dem throw leer kann nichts geworfen werden

    ich halte dein programm design jedoch nicht so für gut weil man exceptions eig nurw enig braucht und wennd ann nur wenn etwas vorhersehbares fehler erzeugt, was man nicht umgehen kann
    aber naja denk ein wenig drüber nach dann schaffst du das, das technische sollte ejtzt kein problem mehr sein



  • Das Problem ist ein anderes. Durch das misslungene Einlesen eines Integers wird das Failbit von Cin gesetzt. Das musst Du dann erst zurücksetzen. So geht es:

    int main()
    {
        int auswahl;
        bool eingabe_ok = false;
    
        do {
            cout << "\n +++++ Triff deine Auswahl: ";
            cin >> auswahl;
    
            if(!cin || auswahl < 1 || auswahl > 2)
            {
                cout << "\n +++++ Bitte korrigieren Sie Ihre Eingabe.";
                std::cin.clear();
                std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
            }else
                eingabe_ok = true;
    
        } while (eingabe_ok == false);
    
        return 0;
    }
    


  • und das problem ja...
    dachte es geht ihm hauptsächlich um das try catch


  • Administrator

    @Skym0sh0,
    throws ? Wir sind hier nicht in Java! lol
    Grundsätzlich hält man es in C++ so, dass man bei der Funktion nichts angibt über die möglichen geworfenen Exceptions, da dies "Fehleranfällig" ist. Gerade in den Templates kann man im allgemeinen nicht wissen, was ein Template für eine Exception werfen kann, wodurch man diese Spezifikation bei der Funktion nicht angeben kann. Zudem wird sie anders angegeben, dass solltest du nochmals nachlesen.

    Zu Exceptions haben wir übrigens drei sehr gute Artikel im Magazin:
    http://magazin.c-plusplus.net/artikel/Exception-Handling
    http://magazin.c-plusplus.net/artikel/Modernes Exception-Handling Teil 1 - Die Grundlagen
    http://magazin.c-plusplus.net/artikel/Modernes Exception-Handling Teil 2 - Hinter den Kulissen

    Und das beschriebene Problem vom Threadersteller hat definitiv mit dem failbit von std::cin zu tun.
    std::ignore sollte man allerdings meiner Meinung nach so benutzen:

    std::cin.ignore(std::cin.rdbuf()->in_avail());
    

    Das Problem ist nämlich, dass nicht alle Betriebsysteme als neue Linie den Linefeed nehmen. Soweit ich weiss, hat man in diesem Punkt keine Garantie. Kann mich da aber auch täuschen. Jedenfalls hat man bei meinem Beispiel sicher alles weg, was drin ist, ausser die Standardimplementation ist fehlerhaft, aber dann ist Hopfen und Malz verloren 😉

    Im übrigen, man kann auch einen std::cin dazu bringen, dass er bei einem Fehler eine Exception wirft:

    std::cin.exceptions(std::istream::eofbit | std::istream::failbit | std::istream::badbit);
    

    http://www.cplusplus.com/reference/iostream/ios/exceptions.html

    Auf die bool Variable kann man übrigens auch verzichten. Indem man eine Endlosschleife und eine break Anweisung nimmt 😉

    Und wenn man noch ganz fanatisch ist, kann man sowas in eine Templatefunktion auslagern, damit man für alle Typen eine entsprechend geprüfte Eingabe hat. Als Parameter kann man dann ein Eingabetext, Fehlertext und als Referenz die zu befüllende Variable übergeben 🙂

    Grüssli



  • naja hab noch nicht so viel mit exceptions gemacht weil man sie ja eig ganz gut vermeiden kann bei kleineren simplen programmen

    naja das failbit ist zwar das fehlerproblem aber er will doch eigendlich exception handling üben...

    von daher meinte ich das

    PS: und ja meine erste richtige programmiersprache war java xD machen wir derzeitig auch in der schule


Anmelden zum Antworten