exit und return



  • das muß nicht unbedingt "tief" sein (btw, ab wann gilt eine Situation als "tief verschachtelt"), das reicht schon, wenn der Fehler in einer direkt aufgerufenen Funktion auffällt:

    double sqrt(double x)
    {
    /*
      die Funktion hat keine Ahnung, woher der übergebene Wert stammt - oder was sie
      mit ungültigen Werten machen sollte, also wirft sie eine Exception und übergibt damit
      dem Aufrufer die Verantwortung
    */
      if(x<0)
        throw std::invalid_argument("keine Wurzeln aus negativen Zahlen erlaubt");
      ...
    }
    
    ...
    double input;
    cin>>input;
    /*
      wenn du jetzt schon merkst, daß du mit der Eingabe nicht weiterrechnen
      könntest, kannst du noch vernünftig reagieren und den Nutzer aufmerksam machen
    */
    cout<<sqrt(input);
    ...
    


  • tweenki schrieb:

    in c++ in 21 Tagen wird das irgendwie ganz anders erklärt. ich kapier des dort jedenfalss nicht...

    Sorry, aber das liegt in der Natur der wirklich schlechten Buchreihe.

    Zum Exceptionhandling:

    Eine Exception sollte man an dem Punkt auslösen (Strichwort: throw) wo ein Fehler auftritt, der nicht direkt an dieser Stelle behandelt wird wo er eintritt.

    Auf eine Exception sollte man an der Stelle reagieren wo man sie sinnvoll behandeln kann.

    Nehmen wir einfach mal als Beispiel das du einige Mathefunktionen in einen eigenen Header ausgelagert hast, damit du sie unter verschiedenen Umgebungen benutzen kannst. Damit du nicht von der GUI abhängig bist und sie wirklich überall verwenden kannst, ist es nicht möglich bei einer fehlerhaften Übergabe (z.B. eine 0 beim Dividenten) den Anwender zu bitten die Zahl korrigiert einzugeben. Da du also in der Funktion keine Möglichkeit hast Sinnvoll auf den Fehler zu reagieren, musst du eine andere Möglichkeit anbieten wie man auf diesen Fehler reagieren kann.

    Bei den klassischen Rückgabewerten hast du das Problem das sie zum einen den Rückgabewert belegen (im Falle einer Mathematischen Funktion hätte ich gerne die Möglichkeit einige Aufrufe zu schachteln) und auch schnell vergessen werden können. Eine andere Möglichkeit wäre z.B. den Fehlercode als Referenz in den Parametern mitzuführen. Aber grade an dem Beispiel der geschachtelten Funktionen bekommt man hier ggf. das Problem das eine fehlerhafte Rückgabe andere verherende Auswirkungen in weiteren Funktionen mit sich bringt.

    Also was macht man: Man löst im Fehlerfall in der entsprechenden Funktion eine Exception aus. Dadurch wird der Programmfluß an dieser Stelle abgebrochen (Anweisungen die danach kommen werden nicht mehr beachtet, lokal erzeugte Objekte aber bereinigt [Achtung: Kein delete bei Pointern - Ich liebe Smartpointer]) und erst mit dem catch des aktiven try-Blockes weitergemacht. Wenn man den exceptions noch unterschiedliche Typen verpasst, kann man diese auch Unterschiedlich in den catchblocken behandeln.

    cu André



  • tweenki schrieb:

    ...
    zu was zählt man alles exceptions? ....

    Mach's Dir doch nicht so schwer !
    Dir ging es doch um eine konkrete Situation, in der Du sagst "Hier will ich gar nicht mehr weitermachen" ... und da wirfst Du halt eine Exception.

    Eine "allgemeingültige und vollständige" Regel gibt's sowieso nicht. Davon zeugen z.B. die ewig langen Threads zu diesem Thema hier im Forum.
    Am Besten machst Du erstmal selbst Erfahrungen mit dem Thema.

    Gruß,

    Simon2.



  • tweenki schrieb:

    kennt jemand ein tut wo das gut erklärt wird?

    Eine Exception wirft man immer dann, wenn (Design by Contract sollte man im Hinterkopf haben) man die Postcondition einer Funktion/Methode nicht einhalten kann.

    Was den konkreten Einsatz von Exceptions anbelangt. Unbedingt die Bücher von Herb Sutter anschauen, da man einige Regeln beachten muß, damit die eigenen Klassen exception safe bzw. exception neutral sind.

    Wenn eine Exception geworfen wird, beginnt das sogenannte "stack unwinding", alle Objekte auf dem Stack werden destruiert und die Ausführung "springt im Stack zurück" solange bis irgend eine Stelle im Programm die Exception abfängt. Im schlimmsten Fall wird das Programm terminiert. Leider sind Zeiger PODs und damit passiert mit ihnen exakt gar nichts, es können so Speicherlöcher entstehen. Deshalb sollte man SmartPointer o.ä. einsetzen. Was alles zu beachten ist steht in recht gut erklärt in den Büchern von Sutter.



  • Fellhuhn schrieb:

    return ist nur für Funktionen/Methoden, nicht für das eigentliche Programm.

    Der saubere Weg ein Programm zu verlassen ist es aus main zu beenden, entweder implizit oder durch das explizite return mit Code.

    exit hat den häßlichen Seiteneffekt, daß die Destruktoren von statischen Objekten nicht aufgerufen werden. Wenn man irgend welche Singletons ö.ä. hat, kann das problematisch sein.



  • ~john schrieb:

    Fellhuhn schrieb:

    return ist nur für Funktionen/Methoden, nicht für das eigentliche Programm.

    Der saubere Weg ein Programm zu verlassen ist es aus main zu beenden, entweder implizit oder durch das explizite return mit Code.

    exit hat den häßlichen Seiteneffekt, daß die Destruktoren von statischen Objekten nicht aufgerufen werden. Wenn man irgend welche Singletons ö.ä. hat, kann das problematisch sein.

    Habe ich was anderes behauptet?



  • Fellhuhn schrieb:

    ~john schrieb:

    Fellhuhn schrieb:

    return ist nur für Funktionen/Methoden, nicht für das eigentliche Programm.

    Der saubere Weg ein Programm zu verlassen ist es aus main zu beenden, entweder implizit oder durch das explizite return mit Code.

    exit hat den häßlichen Seiteneffekt, daß die Destruktoren von statischen Objekten nicht aufgerufen werden. Wenn man irgend welche Singletons ö.ä. hat, kann das problematisch sein.

    Habe ich was anderes behauptet?

    Naja, es hatte sich schon so angehört als würdest du exit für das Beenden in betracht ziehen.

    Un der Unterschied zwischen exit und return ist etwa so, als wenn man in ein Hochhaus mehrere Treppen und Türen hinter sich gebracht hat, und sich dann überlegt wie man wieder das Haus verlässt:
    return: Man geht wieder durch die Türen und Treppen zurück und verlässt damit das Hochhaus.
    exit: Man nimmt das nächstbeste Fenster.

    Ja, es kann gut gehen. Aber mit Sicherheit nicht immer ;p

    cu André



  • Eben, wenn du du mit "return" die letzte Treppe nimmst, bist du da wo du auch durchs "exit" im 20. Stock angekommen wärst. Allerdings in einem etwas unschöneren Zustand.

    exit braucht man eigentlich nicht, Exceptions können das ebenso, und dazu sauber, regeln.

    Wobei mir bei den Exceptions bei C++ immernoch das finally fehlt...



  • Fellhuhn schrieb:

    Wobei mir bei den Exceptions bei C++ immernoch das finally fehlt...

    Wobei du die meisten derartigen Situationen durch RAII lösen kannst - am Funktionanfang legst du ein Objekt an und im Destuktor führt es alle notwendigen Aufräumarbeiten auf (und der wird sowohl im Regelfall als auch beim Stack Unwinding ausgeführt).



  • Wirkt unsauber aber sicher eine bessere Möglichkeit als den CleanUp-Code mehrfach aufzuführen.



  • Fellhuhn schrieb:

    Wirkt unsauber aber sicher eine bessere Möglichkeit als den CleanUp-Code mehrfach aufzuführen.

    finally wälzt die Veranwortung wieder auf den Nutzer der Klasse und nicht auf den Designer einer Klasse ab. Die Realität zeigt, daß der Nutzer sich mit den Problemen nicht herumschlagen will. Insofern ist finally schlechter als RAII.



  • ~john schrieb:

    finally wälzt die Veranwortung wieder auf den Nutzer der Klasse und nicht auf den Designer einer Klasse ab. Die Realität zeigt, daß der Nutzer sich mit den Problemen nicht herumschlagen will. Insofern ist finally schlechter als RAII.

    Weshalb ich auch der Meinung bin C++ braucht kein finally. Das verleitet nur zu unsauberer Programmierung 😉



  • ~john schrieb:

    exit hat den häßlichen Seiteneffekt, daß die Destruktoren von statischen Objekten nicht aufgerufen werden. Wenn man irgend welche Singletons ö.ä. hat, kann das problematisch sein.

    du verwechselst das verhalten mit abort.
    exit ruft die destruktoren von statischen objekten sehr wohl auf.
    nur automatische objekte müssen nicht unbedingt alle zerstört werden.

    btw. um sicher zu gehen, dass das passiert, empfiehlt der standard das werfen einer ausnahme, die in main gefangen wird. dort kann man ja dann auch exit aufrufen, wenn man lust hat (🙄 )



  • LordJaxom schrieb:

    ~john schrieb:

    finally wälzt die Veranwortung wieder auf den Nutzer der Klasse und nicht auf den Designer einer Klasse ab. Die Realität zeigt, daß der Nutzer sich mit den Problemen nicht herumschlagen will. Insofern ist finally schlechter als RAII.

    Weshalb ich auch der Meinung bin C++ braucht kein finally. Das verleitet nur zu unsauberer Programmierung 😉

    Um nicht nochmal dasselbe zu schreiben: 100% 👍

    Gruß,

    Simon2.



  • queer_boy schrieb:

    du verwechselst das verhalten mit abort.

    Mag sein, jedenfalls bleibt bei exit ein anderer Pferdefuß im Spiel, das Stack unwinding wird nicht gemacht. Ergo, läßt man von exit lieber die Finger. Es kann nichts, was return aus main nicht auch könnte. abort kann ja zu Debugging Zwecken ganz brauchbar sein.


Anmelden zum Antworten