Try Catch/Exceptions



  • Student_x schrieb:

    1. Wozu dient das throw in einer Methodensignatur? "void MyFunc() throw (MyError){}"
    Hintergrund: Nehmen wir an eine Methode wirft selbst eine Exep vom Typ X und innerhalb der Methode wird eine Funktion aufgerufen die eine Exception vom Typ Y wirft, was hat es dann zu sagen das die Methode eine Exception vom Typ X wirft, wo doch auch ganz andere Dinge (Typ Y) geworfen werden könnten? Wozu (warum) muß ich das angeben?

    Zur Designzeit is das als eine Art Vertrag zu sehen. Du kannst dann davon ausgehen das diese methode nur die Exceptions wirft die in dieser Liste definiert sind. Wenn du etwas anderes wirftst, wird dieser Vertrag verletzt. Ein Anderes Beispiel wäre ein 3rd Party Komponente wo du nur das Interface siehst, und damit auch die Exceptions die es wirft.(rein hypothetisch natürlich, es ist ja nur ein Vertrag, und die können schon verletzt werden. Was das dann bedeutet is eigentlich nur um festzustellen wer an der ganzen Misere schuld ist:)

    2. Wie organisiert man Exceptions? Wird in der main() oder Hauptausgabe Routine ein großer TryCatch Block gemacht und alles aufgefangen um es dort in Messages für den User zu übersetzen?

    Exceptions werden dort behandelt wo es am meisten Sinn ergibt. Wenn du eine Klasse "File" hast, dann würde es Sinn machen darin oder eine Ebene darunter (darüber eigentlich, stack wächst ja nach unten) die Exception abzufangen. main() hat damit gar nix zu tun, sondern es geht dabei um Struktur, sinnvollen Abfang und Reaktion auf Ereignisse.
    Du musst dir also überlegen, wo es Sinn macht, und wie du am besten recovern kannst.

    3. Als Exception wollte ich noch keine Objekte werfen. Ich dachte eher an Enums. Sorgt der Kompiler dafür das sich die Enums nicht überschneiden oder muß ich manuell jedem Enum Member ein Integer zuweisen? (Überschneiden=Eine Routine wirft FileError=-1 und eine andere Methode wirft NotEnoughMem=-1) Wie kann man das dann auseinanderhalten wenn beides -1 ist?

    Um ehrlich zu sein (aber es sei dir natürlich überlassen), versteh ich den Grund nicht. Exceptions sind sehr wertvoll und können mehr Informationen beinhalten als die typisierte variable ansich. Mach einen namespace und erstelle klassenstubs die du dann voneinander ableiten kannst (oder auch nicht) und individuell werfen kannst. Ich glaube auf lange sicht bist du um einiges glücklicher damit.



  • Nur so nebenbei: Exception Specifications die nicht "throw()" sind halte ich für groben Unfug.
    In langlebigen Projekten kann das schnell zu sehr unerwünschten Zuständen führen, nämlich spätestens dann wenn man irgendwo eine Exception Klasse auftrennt, oder in einer Basis-Funktion auf einmal eine neue Exception werfen muss.

    Dann darf man hunderte andere Funktionen bzw. deren Exception Specifications angucken und entsprechend anpassen. Jeicks.

    Ausserdem verführt es dazu Exceptions zu "transformieren", also in Library A, Schicht X alle Exceptions von anderen Libraries und/oder Schichten zu fangen und "eigene" draus zu machen -- oft nur um keine zusätzlichen Dependencies über die Exception Specifications zu bekommen (=weil man ja in den Headerfiles der Library X sonst Typen der Library Y referenzieren müsste). Was IMO eigentlich fast immer ganz grosser Quatsch ist. (Exceptions sollte man einfach "durchfliegen" lassen wenn man sie an der Stelle nicht endgültig behandeln kann und es nicht notwändig ist dass der User weiss was genau wo schiefgegangen ist)

    Exception Specifications = BÖSE
    hugh



  • hustbaer schrieb:

    Nur so nebenbei: Exception Specifications die nicht "throw()" sind halte ich für groben Unfug.
    In langlebigen Projekten kann das schnell zu sehr unerwünschten Zuständen führen, nämlich spätestens dann wenn man irgendwo eine Exception Klasse auftrennt, oder in einer Basis-Funktion auf einmal eine neue Exception werfen muss.

    Dann darf man hunderte andere Funktionen bzw. deren Exception Specifications angucken und entsprechend anpassen. Jeicks.

    Ausserdem verführt es dazu Exceptions zu "transformieren", also in Library A, Schicht X alle Exceptions von anderen Libraries und/oder Schichten zu fangen und "eigene" draus zu machen -- oft nur um keine zusätzlichen Dependencies über die Exception Specifications zu bekommen (=weil man ja in den Headerfiles der Library X dann auch einmal Typen der Library Y referenzieren müsste). Was IMO eigentlich fast immer ganz grosser Quatsch ist.

    Exception Specifications = BÖSE
    hugh

    Ja ich hatte das auch schreiben wollen, habs aber dann doch gelassen 🙂 Ist natürlich richtig! Man sollte das throw paradigma eigentlich nicht verfolgen. Besonders eben bei grossen Projekten die sowieso schon schwer managebar sind. Und wenn es dann noch über Abstraktionslayer (transformation) und Threads (nu watt?) geht, BOOM!



  • C++ taugt nicht für exceptions. Die throws angabe ist in C++ völlig sinnlos, weil es keine Compileerrors gibt, wenn man die Exception nicht fängt. Arbeitet mal vernünftig mit Java Exceptions und ihr werdet sehen, wie gut das auch in sehr großen Projekten geht. Wenn das vernünftig vom Compiler unterstützt wird, dann is da nix mit BOOM.



  • Lies dir dazu doch einfach mal das hier durch zum Thema Exceptions C++/Java eher ein neuer flame entsteht.
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-176061



  • Hi,

    mich stört an exception spec's in C++ im Wesentlichen, dass sie erst zur Laufzeit (wenn überhaupt) ausgewertet werden. Ansonsten kann ich hustbaers Pragmatismusansatz zwar verstehen, sehe das aber ein wenig anders.
    Natürlich kann man auf exc-Spec. verzichten, aber das Problem, wie man Fehlerbehandlung über API-Grenzen hinweg machen soll, wird man darüber ja nicht los. Exc-Spec. bieten einem damit lediglich einen Formalismus für die Definition...
    (wobei es vielleicht wirklich ungeschickt ist, dies auf Funktionsebene festzulegen...)

    Gruß,

    Simon2.



  • Simon2 schrieb:

    mich stört an exception spec's in C++ im Wesentlichen, dass sie erst zur Laufzeit (wenn überhaupt) ausgewertet werden.

    Anders geht es ja nicht wirklich, es sei denn, du machst die Spezifikationen für jede Funktion verpflichtend. Denn ansonsten kann der Compiler ja nicht wissen, ob die Funktionen, die du in einer anderen Funktion aufrufst, verbotene Exceptions werfen können. Der Compiler kennt ja oft nicht die interne Definition aller Funktionen.

    Felix



  • Das Problem von dem ich spreche existiert in Java genauso.
    In der Standardlibrary wird das oft so gelöst dass eine Funktion dann einfach irgendeine unchecked Exception wirft wenn die passende checked Exception nicht in der Exception Spec. steht. (Und dass die nicht drin steht... liegt eben oft daran dass etwas übersehen wurde.)

    Und das ist genau das Problem welches ich meine: wenn man an "Basis-Libraries" arbeitet, dann kommt es garnicht gut wenn man deren Interface ändern muss. Exceptions Specs zwingen einen manchmal dazu, und deswegen mag ich sie nicht. Die andere Lösung, einfach *irgendwas* zu schmeissen was in der Spec. steht halte ich für einen noch gröberen Fehler.

    @Simon2:
    Ich finde Fehlerbehandlung über API-Grenzen hinweg ist oft recht einfach. In den meisten Fällen reicht es zu wissen dass etwas daneben gegangen ist, und dass man eine Fehlermeldung anzeigen kann. Beides ist mit std::exception möglich.
    Wenn man zusätzliche Informationen benötigt wird es natürlich schwieriger.



  • Erstmal vielen Dank für die Antworten. 🙂
    Dann werde ich mein Programm erstmal umstricken müssen. Die throw Anweisungen werfe ich dann überall aus den Funktionssignaturen raus.



  • hustbaer schrieb:

    Das Problem von dem ich spreche existiert in Java genauso.
    In der Standardlibrary wird das oft so gelöst dass eine Funktion dann einfach irgendeine unchecked Exception wirft wenn die passende checked Exception nicht in der Exception Spec. steht. (Und dass die nicht drin steht... liegt eben oft daran dass etwas übersehen wurde.)

    Beispiele.



  • Phoemuex schrieb:

    Simon2 schrieb:

    mich stört an exception spec's in C++ im Wesentlichen, dass sie erst zur Laufzeit (wenn überhaupt) ausgewertet werden.

    Anders geht es ja nicht wirklich, es sei denn, du machst die Spezifikationen für jede Funktion verpflichtend....

    Wieso ? Der Default ist halt "throws(...)" .... genau wie jetzt. Oder auf "throws()" - ginge auch.

    Gruß,

    Simon2.



  • hustbaer schrieb:

    ...
    @Simon2:
    Ich finde Fehlerbehandlung über API-Grenzen hinweg ist oft recht einfach. In den meisten Fällen reicht es zu wissen dass etwas daneben gegangen ist, und dass man eine Fehlermeldung anzeigen kann. Beides ist mit std::exception möglich.
    Wenn man zusätzliche Informationen benötigt wird es natürlich schwieriger.

    Ähhh also ich habe in meinen Schichten APIs zu Corba, MQSeries (C), einem Persistenzframework, .... viele davon können überhaupt nichts mit std::exception (oder gar irgendeiner Exception) anfangen.
    Ganz zu schweigen von meinen "Clienten" (ecCash-Terminals haben's nicht so mit der Anzeige von "std::exception::what()" 😉 )...

    Der Fall, den Du skizzierst, ist auch der einfachste überhaupt: Eigentlich überhaupt kein Fehlerhandling im Programm, sondern ein Abwälzen auf einen (menschlichen) User.
    Wenn Dein Programm aber z.B. Alternativrouting, Retry, Eskalation, ... in Fehlersituationen einsetzen soll, muss der/irgendein AufruferPG schon "verstehen" können, wo das Problem liegt - und da wird's dann hakelig. Da wird dann "Absprache" notwendig.

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Wenn Dein Programm aber z.B. Alternativrouting, Retry, Eskalation, ... in Fehlersituationen einsetzen soll, muss der/irgendein AufruferPG schon "verstehen" können, wo das Problem liegt - und da wird's dann hakelig. Da wird dann "Absprache" notwendig.

    Jo. Sowas würde ich vermutlich auch nicht über Exceptions machen.



  • hustbaer schrieb:

    Simon2 schrieb:

    Wenn Dein Programm aber z.B. Alternativrouting, Retry, Eskalation, ... in Fehlersituationen einsetzen soll, muss der/irgendein AufruferPG schon "verstehen" können, wo das Problem liegt - und da wird's dann hakelig. Da wird dann "Absprache" notwendig.

    Jo. Sowas würde ich vermutlich auch nicht über Exceptions machen.

    Hi,

    ach, exceptions haben IMO den Vorteil, dass sie (durch den speziellen Kontrollfluß) den Code übersichtlich halten können und deswegen setze ich sie eigentlich sehr gerne ein. Aber man braucht eben sehr klare Absprachen, wo/wie sie geworfen/gefangen werden .... und das könnte mit funktionierenden exce-Specs. sehr viel einfacher/standardisierter sein.

    Gruß,

    Simon2.



  • Naja, ich weiss nicht.
    Wie gesagt, ich denke das Problem löst man nicht durch Exceptions Specs.

    Wichtig wäre in C++ erstmal dass Exceptions standardmässig verwendet werden (also in den unzähligen Libs die "da draussen" rumschwirren), und standardmässig welche die von std::exception erben.

    Dann wäre es natürlich fein wenn es soetwas wie "throwable" geben wurde, ggf. mit ein paar netten Funktionen wo ich Infos zu einer Exception dazuhängen kann oder eine "alte" Exception als Grund für eine "neue" eintragen kann.
    Geht natürlich nur wenn alles was geworfen werden kann auch geklont werden kann -- eine Basisklasse die etwas mächtiger ist als std::exception wäre hier nett.

    Aber das sind bei C++ eben leider alles nur träumereien, wenn sowas jemals kommt wird es wohl noch lange dauern fürchte ich.


Anmelden zum Antworten