wo catched man exceptions?
-
Designfrage
Der Sinn von Exceptions ist es ja einen Fehler außerhalb der Funktion zu behandeln, die ihn verursacht hat. Aber wo sonst? Irgendwo zwischen der Fehler-Funktion und main().
Konkretes Beispiel:
Ich hab (unter anderem) drei Funktionen:
1. starteSpiel(), ruft auf:
2. ladeAlleBilderDesSpiels(), ruft auf:
3. ladeEinBild(dateiname).LadeEinBild wirft eine Exception. Soll ladeAlleBilderDesSpiels die Exception dann an starteSpiel() weiterleiten und diese Funktion dann etwas wie "cout<<"Fehler";" machen, oder soll das ladeAlleBilderDesSpiel() selber machen. Könnte es zum Beispiel sein, dass nur eine Klasse mit dem Benutzer interagieren darf?
-
Hi,
eigentlich gibt es nur eine Regel: Man fängt sie da, wo man etwas mit ihr anfangen kann (z.B: einen Retry oder eine alternative Lösungstrategie starten) oder sie fangen muss (z.B. aus technischen Gründen).
Sonst lässt man sie eben fliegen ... dafür sind sie da.
Großer Schwachsinn (und typisch für Anfänger ... habe ich auch lange so gemacht) ist es, immer alle Exceptions an jeder Aufrufschicht zu fangen - bringt nichts und macht nur Ärger.
Gruß,
Simon2.
-
Jetzt hier im Beispiel muss ich ja schon nachgucken, ob es die Bilddatei noch gibt. Die Frage ist nur wo ich dem Benutzer sagen soll, ob sie existiert. Kann schon sein, dass ich etwas fundamental falsch verstanden habe, aber ich hab noch nicht verstanden was.
Es handelt sich um eine Exception, die von einer Funktion geworfen wird, die ich selbst geschrieben habe, deshalb könnte ich sie theoretisch auch weglassen und den Fehler direkt da melden.
-
obbba schrieb:
Es handelt sich um eine Exception, die von einer Funktion geworfen wird, die ich selbst geschrieben habe, deshalb könnte ich sie theoretisch auch weglassen und den Fehler direkt da melden.
also ich würde die exception da lassen, das kann nie schaden

Und fangen musst du sie auch nicht unbedingt, denn wenn ein Bild etc. fehlt, ist das programm ja vielleicht sowieso nicht in der Lage, richtig zu funktionieren.
Du kannst die Exception auch einfach fangen, eine debug-message ausgeben, und sie dann weiterwerfen, sodass sich das programm trotzdem beendet.try { // blablub } catch (...) { // hier ne message ausgeben throw; // hier die gefangene exception 'weiterwerfen' }
-
exceptions erscheinen dem neuling auch etwas nervig (mir ging es so),
sind aber praktisch (dafür sind sie gemacht) um Fehler zurückzugeben.Beispiel:
int faculty (int value) {//value muss grösser null sein if (value<0) return -1; //Fehler-Code => -1 : Value ist negativ if (value==1) {return 1;} else {return value*falculty(value-1);} }Es werden "ungültige Werte" als Fehler-Code zurückgegeben. Aber was ist wenn keine falschen Rückgabewerte verfügbar sind? Dafür gibt es die Exceptions.
Der Vorteil der Exception ist, dass der Fehler-Behandlungs-Code schon optisch schön von dem regulären Code abgehoben ist. Unter Java gelten/sind Exceptions als langsam, unter cpp weiss ich nicht.
Unter cpp kannst du jeden beliebigen Typen als Exception werfen:
void fakeFunction(int value) {throw "Böse Exception! Erschiessen Sie Ihren Computer!";} void testFunction() {try {fakeFunction(123);} catch (char* exception) {std:cout<<exception;}}Ich stehe mit meiner Meinung oft alleine, aber mein Tip:
Guck dir das Exception-System von Java an! Java benutzt als Exception nur Objekte, deren Klassen SubKlassen der BasisKlasse Exception sind. Es werden also immer spezielle Exception-Typen geworfen.
Du müsstest dir ebend eine Klasse für die Exception schreiben:class MeineSchlechteLauneException { private: char* grund; public: char* toString() {return strcpy(this->grund);} MeineSchlechteLauneException (char* grund) {this->grund=strcpy(grund);} }; void testFunction() {try {fakeFunction();} catch (MeineSchlechteLauneException e) {cou<<"da kann man nix machen!";} void fakeFunction() {throw new MeineSchlechteLauneException("Ist halt so!");Nur den Mechanismus der impliziten TypenUmwandlung, dass wenn du generell alle Exceptions fängst, indem du die BasisKlasse aller Exceptions fängst: catch (Exception e) z.B. auch alle NullPointerException gleich mit fangen kannst, müsstest du erst aufwendig/unpraktisch implementieren.
Aber dennoch halte ich die zu 80% übertragbare Systematic für sinnvoll und den Code beim Schreiben für aussagekräftiger. Zur Performance kann ich nix sagen. Exceptions lassen sich manchmal einfach nicht mehr sinnvoll umgehen. Ich hasste sie unter Java (mann schon wieder) und heute vermisse ich unter CPP ihre Systematik von Java.
Fazit: Exception sind keine Details der Sprache sondern wichtig um "sprachlich" Fehler zu handhaben.
Tip: Austesten bist du es geschnallt hast und ohne zu zögern dir welche schreiben würdest.
Nun die direkte Antwort: OOP! Frage dich in welcher Klasse das KnowHow zu stecken hat um diesen Fehler zu behandeln! Stell dir vor die Objekte sind Fachleute in ihrem Gebiet abhängig davon welche Klasse sie besucht haben und sind in der Lage alle Probleme ihre AbstraktionsEbene zu behandeln.
Die Probleme unterliegender AbstraktionsEbenen sollten nicht ankommen und Probleme die darüberliegen werden weitergereicht. Stell dir vor ein Arbeiter in einem Betrieb arbeitet an einer Maschine und sie geht kaputt=> Meister bescheid sagen Meister entscheidet: "jemand soll sie reparieren" oder er fragt seinen Betriebsleiter: "wir brauchen eine neue Maschine!". Stell dir dein Programm also vor wie ein Unternnehmen mit klar abgegrenzten Aufgabenbereichen und Code an falscher Stelle sind wie Arbeiter die ungeeignete Arbeiten verrichten.
-
Was mir oft auch hilft: Vornherein eine Liste machen mit Fehlern, die auftreten könnten und zu jedem Fehler genau spezifizieren, wie du darauf reagieren willst. Bei dem Beispiel Bild-Laden können ja mehrere Fehler auftreten: Es kann sein, dass sie nicht existiert, oder sie existiert aber du kannst nicht lesend darauf zugreifen. Bei der Nicht-Existenz könntest du z.B. den Benutzer fragen, ob er den Pfad ändern will oder ob's nochmal versucht werden soll. Beim nicht-zugreifen-können könntest du den Benutzer bitten, das entsprechende blockierende Programm zu schließen oder ihm die Möglichkeit zu geben, abzubrechen. Alternativ können auch beide Fehler zum sofortigen Ende des Programms führen.
Meine Erfahrung ist, dass, wenn ich weiß, wie ich auf den Fehler reagieren will, auch recht schnell entscheiden kann, an welcher Stelle im Code der Fehler abgefangen werden soll. Das ist zwar etwas mehr Vorarbeit, rechnet sich imho aber schnell wieder auf.
-
obbba schrieb:
...deshalb könnte ich sie theoretisch auch weglassen und den Fehler direkt da melden.
... und dann ?
Die Stärke der Exception liegt darin, dass Du Dich nicht mehr darum kümmern musst - im Gegensatz zu Fehlercodes, die man abfragen muss ... was man vergessen kann.
(ich könnte hier nochmal wiederholen, was die Anderen schon so schön geschrieben habe, erspare uns das aber
)Gruß,
Simon2.
-
obbba schrieb:
Designfrage
Konkretes Beispiel:
Ich hab (unter anderem) drei Funktionen:
1. starteSpiel(), ruft auf:
2. ladeAlleBilderDesSpiels(), ruft auf:
3. ladeEinBild(dateiname).Wenn du damit leben kannst dass ein einzelnes Bild nicht geladen werden kann, dann solltest du ueberlegen, ob ladeEinBild() tatsaechlich werfen muss. Wenn du ohne das Bild nicht leben kannst, kannst du werfen und ladeAlleBilde() wirft einfach weiter. starteSpiel() koennte dann entscheiden, ob es einen Modus ohne Bilder gibt, oder ob du den User einen alternativen Pfad fuer die Bilder eingeben laesst oder selbst d=eine Suche danach laufen laesst. Die Entscheidung triffst du dann, nachdem du die Exception gefangen hast und ja jetzt weisst, dass da was mit einem der Bilder nicht geklappt hat. Sollte das Spiel allerdings ohne die Bilder nicht leben koennen, wirft auch starteSpiel() einfach weiter und irgendwer anderes verarbeitet das (die main(), unexpected() oder terminate()). Es koennte z.B. einfach das ganze Spiel abgebrochen werden mit der Meldung, dass da was derbe kaputt ist und die Config geaendert werden muesste oder gleich das Ganze Programm neu installiert. Kurz udn gut: es ist alles Ermessenssache und von der jeweiligen programmlogik abhaengig, wie weit man die Exception fliegen laesst. (je weiter man sie fliegen laesst, desto mehr Funktionen und Klassen sollten allerdings der strong guarantee entsprechen um ressourcen lecks zu vermeiden)