try catch in jeder funktion?



  • pumuckl schrieb:

    ...
    Punkte, die keine Ausnahme sein sollten:
    ...
    Punkte, die Ausnahmen sein koennen:
    ...
    Strittige Punkte sind beispielsweise:
    ...

    Hmmm - ich weiß nicht.
    Das ist sehr stark "Konvention".
    Für mich ist eine exception dann das Mittel der Wahl, wenn eine Funktion ihre fachliche Aufgabe nicht erfüllen konnte und das dem Aufrufer mitteilen will.
    Das bedeutet natürlich auch, dass eine Funktion "sucheEintraege()" KEINE exception wirft, wenn sie keinen gefunden hat - weil "kein Eintrag" ein fachlich definierter Zustand ist.
    Das setzt allerdings eine saubere fachliche Modellierung voraus, in denen wirklich alle Fälle (auch die "Ausnahme-/Fehlerfälle") abgedeckt sind und leider ist sowas eher selten. Ich bekomm' immer die Krise wenn in einer fachlichen Beschreibung nur steht: "Der Wert ist zu bestimmen". 🙄

    Sagen wir mal so: Immer wenn man in Versuchung steht, einen Fehlercode via return oder in einen Parameter codiert zurückzugeben, würde ich eine exception vorziehen.

    (Ausnahmen bestätigen wie immer die Regel)

    Gruß,

    Simon2.



  • Konrad Rudolph schrieb:

    pumuckl schrieb:

    Punkte, die keine Ausnahme sein sollten:
    - der User moechte eine Datei oeffnen, die nicht existiert.

    Und das ist eben genau falsch. In dieser Situation hat man gar keine andere Wahl, als mit einer Ausnahme zu reagieren denn es könnte gut sein, dass der Benutzer sehr wohl eine existente Datei ausgewählt hat, die aber zwischen der Auswahl und dem Überprüfen auf Existenz (selbst, wenn das direkt hintereinander erfolgt) gelöscht worden ist oder das Trägermedium entfernt wurde.

    Man prüft auch nicht auf Existenz und öffnet dann, sondern man öffnet und prüft, ob das geklappt hat. Da man hier davon ausgehen muss, dass die Datei nicht existiert, ist das keine Ausnahme, sondern regulärer Kontrollfluss.



  • Simon2 schrieb:

    Für mich ist eine exception dann das Mittel der Wahl, wenn eine Funktion ihre fachliche Aufgabe nicht erfüllen konnte und das dem Aufrufer mitteilen will.
    Das bedeutet natürlich auch, dass eine Funktion "sucheEintraege()" KEINE exception wirft, wenn sie keinen gefunden hat - weil "kein Eintrag" ein fachlich definierter Zustand ist.

    Sagen wir mal so: Immer wenn man in Versuchung steht, einen Fehlercode via return oder in einen Parameter codiert zurückzugeben, würde ich eine exception vorziehen.

    Öhm, wäre das Ergebnis "kein Eintrag" nicht eine Art Fehlercode? Wo ziehst du denn da die Trennlinie?

    (Ausnahmen bestätigen wie immer die Regel)

    Aber nur, wenn sie gefangen werden 😉



  • Bashar schrieb:

    ...
    Öhm, wäre das Ergebnis "kein Eintrag" nicht eine Art Fehlercode? Wo ziehst du denn da die Trennlinie?...

    Hier ist das einfach fachlich zu modellieren: Die leere Ergebnismenge ist erlaubt.
    std::string::length() gibt auch problemlos 0 zurück...

    Natürlich ist das nicht immer ganz eindeutig - aber deswegen ist es ja auch eher "Richtlinie" und kein "Gesetz".

    Gruß,

    Simon2.



  • Bashar schrieb:

    Man prüft auch nicht auf Existenz und öffnet dann, sondern man öffnet und prüft, ob das geklappt hat. Da man hier davon ausgehen muss, dass die Datei nicht existiert, ist das keine Ausnahme, sondern regulärer Kontrollfluss.

    Wenn die Datei nicht existiert, kann die Funktion ihre reguläre Arbeit (Daten lesen und verarbeiten) nicht erledigen, ergo gibt es einen Fehler.
    (und auch erwartete Fehlerzustände sind immer noch Fehler, die den regulären Ablauf beeinflussen - das muß nicht immer in einer Exception enden, aber es kann)



  • Bashar schrieb:

    Man prüft auch nicht auf Existenz und öffnet dann, sondern man öffnet und prüft, ob das geklappt hat. Da man hier davon ausgehen muss, dass die Datei nicht existiert, ist das keine Ausnahme, sondern regulärer Kontrollfluss.

    it depends. wenn ich mich in einer routine befinde, die bspw nur zum speichern da ist, so ist in dieser routine nichts gegen den fehler machbar (also werfe ich etwas oder lass die von fstream erzeugte exception einfach durch) und die übergeordnete methode kann dann eine sinnvolle fehlermeldung und -behandlung liefern.



  • Konrad Rudolph schrieb:

    denn es könnte gut sein, dass der Benutzer sehr wohl eine existente Datei ausgewählt hat, die aber zwischen der Auswahl und dem Überprüfen auf Existenz (selbst, wenn das direkt hintereinander erfolgt) gelöscht worden ist oder das Trägermedium entfernt wurde.

    Es ist doch eigentlich irrelevant, ob die Datei existiert hat, als der User ihren Namen uebergeben hat. Einzig relevant ist, ob der Versuch, diese Datei zu oeffnen gelingt oder nicht. Wenn ich eine Datei auf ihre Existenz pruefe, kann ich garnicht wissen, ob sie einen Tick vorher noch existiert hat oder ob die Nutzerangaben voellig fiktiv sind. Vor und waehrend der Pruefung stellt die Nichtexistenz der Datei einen ganz normalen Anwendungsfall dar. Danach ist das was ganz anderes, denn da kann man ihre Existenz als gesichert annehmen und es waere eine Ausnahme, wenn sie ploetzlich doch nicht da ist.

    Der Unterschied zwischen Ausnahme und normalem Fehlerfall ist doch der, ob ich etwas als gesichert annehmen kann oder nicht. Wenn etwas gesichert ist, kann ich es als gegeben annehmen und nur in Ausnahmefaellen wird es doch nicht gegeben sein. Wenn es nicht sicher ist, muss ich es ueberpruefen um es sicherzustellen.
    Deshalb geht darum, ob man etwas als Tatsache sieht (z.B dass die Datei existiert, wenn ich ihre Existenz durch eine Pruefung bestaetigt habe) oder nicht.

    Genau deshlab die strittigen Punkte: Die meisten Leute nehmen es als gesichert an, dass genug Speicher fuer ihr Programm zur Verfuegung steht. In dem Fall ist die Exception die richtige Antwort auf eine erfolglose Alloziierung. Wenn man aber weiss, dass der Speicher nicht unbedingt reichen muss, dann muss man das anders handhaben, z.B. indem man den User auffordert, andere Programme zu beenden.

    Nach allem, was ich bisher lesen durfte, ist alles, was einigermassen absehbar und abfangbar ist, mit normaler Fehlerbehandlung abzuhandeln und Ausnahmen eben nur ausnahmsweise zu benutzen.



  • Soviel zum Thema "was ist ein Ausnahmefall?" 😉 Im Endeffekt hängt es doch wieder von der konkreten Anwendung ab, was du als sicher annehmen kannst und was nicht.

    Zum Beispiel: wenn ich mit einem CFileDialog den User nach einer Quelldatei frage, sichert der mir zu, daß diese Datei existiert - wenn dann das Öffnen dieser Datei scheitert, ist das unerwartet. (wenn du den Namen über cin eingegeben hast, ist es vermutlich deine Aufgabe, zunächst festzustellen, ob die Datei existiert)

    Außerdem hatte ich schonmal gesagt, daß nicht jeder Fehler zu einer Exception führen muß. Was ich sofort beheben kann, behebe ich auch sofort (Dateiname ungültig -> Rückkehr zum Anfang und anderen Namen erfragen). Erst wenn ich an der aktuellen Stelle keine Möglichkeit habe, etwas gegen den Fehler zu unternehmen (z.B. weil die Speicherroutine keine Möglichkeit hat, den User über Probleme zu informieren), werfe ich eine Exception - die dann von der Methode gefangen wird, die den Namen erfragt und das Speichern gestartet hat.



  • pumuckl schrieb:

    ...
    Nach allem, was ich bisher lesen durfte, ist alles, was einigermassen absehbar und abfangbar ist, mit normaler Fehlerbehandlung abzuhandeln und Ausnahmen eben nur ausnahmsweise zu benutzen.

    Hmmm - ist nicht ALLES absehbar, was man überprüft ?
    Wenn ich Speicher anfordere, weiß ich immer, dass er nicht reichen könnte (habe schonmal erlebt oder davon gelesen).
    Wenn ich nicht weiß, dass er nicht reichen könnte, werde ich dafür auch keinen Fehlermechanismus implementieren ...

    Ergo: Man braucht NIE exceptions. 😃

    Gruß,

    Simon2.



  • Simon2 schrieb:

    pumuckl schrieb:

    ...
    Nach allem, was ich bisher lesen durfte, ist alles, was einigermassen absehbar und abfangbar ist, mit normaler Fehlerbehandlung abzuhandeln und Ausnahmen eben nur ausnahmsweise zu benutzen.

    Hmmm - ist nicht ALLES absehbar, was man überprüft ?
    Wenn ich Speicher anfordere, weiß ich immer, dass er nicht reichen könnte (habe schonmal erlebt oder davon gelesen).
    Wenn ich nicht weiß, dass er nicht reichen könnte, werde ich dafür auch keinen Fehlermechanismus implementieren ...

    Ergo: Man braucht NIE exceptions. 😃

    dass hab ich mir nach pumuckls beitrag auch gedacht. eine exception wird ja nicht zufällig erzeugt, sondern, wenn eine variable für irgend eine operation einen ungültigen wert hat. und um sowas rauszufinden muss man irgendwas prüfen. das heißt nicht, dass ungültiger wert == exception, falls das einer flasch verstehen will. alles ist auf irgend einer ebene absehbar, und nur deshalb keine exception zu werfen ist falsch.



  • Simon2 schrieb:

    Bashar schrieb:

    ...
    Öhm, wäre das Ergebnis "kein Eintrag" nicht eine Art Fehlercode? Wo ziehst du denn da die Trennlinie?...

    Hier ist das einfach fachlich zu modellieren: Die leere Ergebnismenge ist erlaubt.
    std::string::length() gibt auch problemlos 0 zurück...

    Die leere Ergenismenge? Bei sucheEintrag hätte ich als Ergebnis einen Index erwartet, keine Menge. Das ist eine vollkommen andere Situation als bei der Länge eines Strings.



  • Simon2 schrieb:

    pumuckl schrieb:

    ...
    Nach allem, was ich bisher lesen durfte, ist alles, was einigermassen absehbar und abfangbar ist, mit normaler Fehlerbehandlung abzuhandeln und Ausnahmen eben nur ausnahmsweise zu benutzen.

    Hmmm - ist nicht ALLES absehbar, was man überprüft ?
    Wenn ich Speicher anfordere, weiß ich immer, dass er nicht reichen könnte (habe schonmal erlebt oder davon gelesen).
    Wenn ich nicht weiß, dass er nicht reichen könnte, werde ich dafür auch keinen Fehlermechanismus implementieren ...

    Ergo: Man braucht NIE exceptions. 😃

    Wenn du aber zu wissen glaubst, dass der Speicher auf jeden Fall immer ausreichen wird, es dir aber nicht leisten kannst, dich auf dieses Wissen zu verlassen, dann kommt die Ausnahme ins Spiel.



  • pumuckl schrieb:

    Wenn du aber zu wissen glaubst, dass der Speicher auf jeden Fall immer ausreichen wird, es dir aber nicht leisten kannst, dich auf dieses Wissen zu verlassen, dann kommt die Ausnahme ins Spiel.

    Und wenn ich zu wissen glaube, daß ich vom Nutzer den Dateinamen einer existierenden Datei übergeben bekommen habe, mir es aber nicht leisten kann, mich auf dieses Wissen zu verlassen? Die Situation sieht genauso aus 😉



  • Bashar schrieb:

    ...
    Die leere Ergenismenge? Bei sucheEintrag hätte ich als Ergebnis einen Index erwartet, keine Menge. Das ist eine vollkommen andere Situation als bei der Länge eines Strings.

    Von der Funktion habe ich nicht geredet, sondern von

    Simon2 schrieb:

    ...dass eine Funktion "sucheEintraege()" ...

    Bei einer "sucheEintrag()"-Funktion hätte ich noch mehr Anfragen an die fachlichen Anforderungen ...u.a.: "Was, wenn ich mehrere passende Einträge finde ?" (oder eben: keinen). Das kann ich so pauschal nicht beantworten, weil es einfach eine deutlich komplexere Anforderung ist.

    Gruß,

    Simon2.



  • Ups, wer lesen kann ... .)



  • pumuckl schrieb:

    ...Wenn du aber zu wissen glaubst, dass der Speicher auf jeden Fall immer ausreichen wird, es dir aber nicht leisten kannst, dich auf dieses Wissen zu verlassen, ...

    ... dann weißt Du aber, dass es DOCH Situationen geben kann, in denen er nicht reicht.

    Ich kann diese Regel höchstens als "Tendenz-Aussage" verstehen: "Je unwahrscheinlicher Dir die Situation erscheint, um so ernster solltest Du das Verwenden einer Exception in Erwägung ziehen." und "Je unwahrscheinlicher es Dir erscheint, um so ... Fehlercode ...".

    Leider ist das bei low-level- oder Querschnittsfunktionen Funktionen fast gar nicht mehr zu unterscheiden, weil ich gar nicht weiß, aus welcher Ausgangsposition ich aufgerufen werde ("Rechnet der Aufrufer vielleicht sogar damit, dass es keine Einträge gibt ?"...).

    Gruß,

    Simon2.



  • @pumuckl:

    Genau deshlab die strittigen Punkte: Die meisten Leute nehmen es als gesichert an, dass genug Speicher fuer ihr Programm zur Verfuegung steht. In dem Fall ist die Exception die richtige Antwort auf eine erfolglose Alloziierung. Wenn man aber weiss, dass der Speicher nicht unbedingt reichen muss, dann muss man das anders handhaben, z.B. indem man den User auffordert, andere Programme zu beenden.

    Nope, ganz böse falsch.

    Wenn man davon ausgeht dass der Speicher immer reichen muss, dann überschreibt (EDIT: redefiniert muss es denke ich richtig heissen) man new und macht ein "terminate()" statt dem "throw bad_alloc" rein! Dann ist das nämlich ein *Fehler* und keine *Ausnahme* mehr.

    Wenn man aber davon ausgeht dass der Speicher evtl. nicht reichen würde, dann verwendet man Exceptions.

    Der Fehler liegt darin dass du Fehler so behandelst wie man Ausnahmen behandeln sollte, und Ausnahmen so behandelst wie man den "Normalfall" behandeln sollte.



  • hustbaer schrieb:

    Wenn man davon ausgeht dass der Speicher immer reichen muss, dann überschreibt (EDIT: redefiniert muss es denke ich richtig heissen) man new und macht ein "terminate()" statt dem "throw bad_alloc" rein! Dann ist das nämlich ein *Fehler* und keine *Ausnahme* mehr.

    Man kann die bad_alloc-Ausnahme auch in der main fangen und das Programm terminieren.

    Und zwischen Fehler und Ausnahme kannst du sowieso nicht sinnvoll unterscheiden, da Fehler eine Ausnahme sein sollten und eine Ausnahme bedeutet, dass ein Fehler aufgetreten ist.



  • Badestrand schrieb:

    ...
    Man kann die bad_alloc-Ausnahme auch in der main fangen und das Programm terminieren....

    KANN man - aber es kann einem irgendwo zwischendrin mit catch(...) weggefangen werden. Das get mit terminate() nicht mehr.
    Außerdem hatte ich das so verstanden: "Was soll man lokal (also in der Funktion, die den Speicher anfordert) tun ?"

    Badestrand schrieb:

    ...
    Und zwischen Fehler und Ausnahme kannst du sowieso nicht sinnvoll unterscheiden, da Fehler eine Ausnahme sein sollten und eine Ausnahme bedeutet, dass ein Fehler aufgetreten ist.

    Es git auch eine Philosophie, die zwischen einem "(harten) Fehler" und einer "Ausnahmesituation" unterscheidet. Vertreter dieser Philosophie verwenden gerne terminate() und assert(). Ich selbst mache das nicht, aber ein exzellenter Externer (wirklich !!) machte das und auch andere Programmierer, die ich sehr schätze, tun es (andere wiederum nicht).

    Gruß,

    Simon2.



  • Um hier auch einmal meine (persönliche) Ansicht zu der Sache kund zu tun:

    Exceptions werfe ich immer dann, wenn eine Funktion (oder Methode) auf Grund Ihrer Vorbedingungen nicht das leisten kann, was von Ihr erwartet wird.

    Ich liebe Beispiele, von daher:

    unsigned int minusFour(unsigned int value);
    

    Gesetzt den Fall, es würde 3 übergeben werden, dann wäre das Ergebnis -1. Da aber ein vorzeichenloser Wert zurückgegeben werden soll, handelt es sich bei der Vorbedingung value=3 um eine Ausnahme, die (aufgrund der exzellenten Dokumentation der Funktion) nicht vorkommen sollte aber eben vorkommen kann.

    Da diese Funktion keine andere Möglichkeit besitzt, diese Situation mitzuteilen (von globalen Fehlerobjekten mal abgesehen), wird eben eine Exception verwendet:

    unsigned int minusFour(unsigned int value) throw(ValueError);
    

    Wenn eine Funktion einen Pointer zurück geben soll, dann hat man hier die Möglichkeit auf NULL zu prüfen, welches ein Wert ist, mit dem man durchaus weiterarbeiten kann. In dem Fall kann auf eine exception verzichtet werden.

    Grüße...

    Heiko


Anmelden zum Antworten