Die Kosten von try und catch



  • Es ging mir jetzt auch nicht um das Beispiel. Ich würde an dieser Stelle selbst nie eine Exceptionbehandlung starten...
    Es gibt mir einfach darum, was es mich kostet, wenn ich einen try Block habe, aber keine Exception geworfen wird. Das Beispiel war einfach das erste, was mir eingefallen ist 😉
    Also Xin hat genau das geschrieben, was ich wissen wollte! Danke!



  • Unter Windows verwendet die Mehrheit aller C++-Anwendungen das Structured Exception Handling das in Windows implementiert ist. Kannst ja mal danach suchen in der msdn, wenn dich interressiert wie das im Detail ablauft.



  • ja werde ich mir auch noch einmal anschauen 🙂



  • Sobald Du also 'try' sagst, muss erstmal ein Zeiger aktualisiert werden, der sagt wohin geworfen werden soll.
    Sobald Du den 'try' Bereich verlässt, muss der Zeiger wieder zurückgesetzt werden.

    Nicht unbedingt. Ein Compiler kann es auch so machen dass er schöne Tables erstellt, wo er dann bei jedem "throw" mit Hilfe des instruction-pointer und des Stacks nachgucken kann, welche catch Blöcke alle "aktiv" sind. Die Liste klappert die Runtime dann der Reihe nach durch bis sie einen passenden findet. Welchen Code er beim Stack-Unwinding ausführen muss kann er auch über Tables + instruction pointer + den Stack ermitteln.

    So ein Compiler muss dann nix an Code erzeugen was ausgeführt werden würde ohne dass wirklich eine Exception fliegt.



  • hustbaer schrieb:

    Sobald Du also 'try' sagst, muss erstmal ein Zeiger aktualisiert werden, der sagt wohin geworfen werden soll.
    Sobald Du den 'try' Bereich verlässt, muss der Zeiger wieder zurückgesetzt werden.

    Nicht unbedingt. Ein Compiler kann es auch so machen dass er schöne Tables erstellt, wo er dann bei jedem "throw" mit Hilfe des instruction-pointer und des Stacks nachgucken kann, welche catch Blöcke alle "aktiv" sind. Die Liste klappert die Runtime dann der Reihe nach durch bis sie einen passenden findet. Welchen Code er beim Stack-Unwinding ausführen muss kann er auch über Tables + instruction pointer + den Stack ermitteln.

    So ein Compiler muss dann nix an Code erzeugen was ausgeführt werden würde ohne dass wirklich eine Exception fliegt.

    Bei aktueller Programmierweise, wo immer mehr try-Blöcke propagiert werden, dürfte diese Tabelle recht groß ausfallen und die Suche nach dem richtigen Eintrag dadurch
    recht langwierig.
    Weiterhin springen viele Leute auf einen Exception-Hype auf, so dass außergewöhnliche Rückgaben wie z.B. Dateiende inzwischen als Exception geworfen werden. Prüft man nun auf die Exception Dateiende, wird diese Exception-Tabelle-Tabelle Liste bei jeder zu lesenden Datei durchwühlt, um dann in der richtigen Exception-Tabelle die richtige Reaktion auf die Exception zu finden.

    Die Idee der Exception finde ich hervorragend, es kann Code, der nur ausnahmsweise fehlschlagen kann, übersichtlicher machen.
    Aber die Folgekosten sind mir persönlich zu hoch.

    [Das unsinnige Argument, der schnellen CPUs möge man mir bitte ersparen...]



  • @Xin:
    Das Suchen in den Tabellen, die, wie du richtig sagst, recht gross werden können, wird nicht notwendigerweise langsam, wenn die Datenstruktur in der man diese Tabellen ablegt entsprechend ist (Baum, Skip-List, wo's Sinn macht evtl. nen Hash etc.). Und dass die Tabellen gross werden ist wirklich nur dann von Bedeutung wenn man wenig Speicher hat - die müssen ja nicht bei Programmstart gleich vollständig in den Speicher geladen werden - von daher dauert das auch nicht so schlimm lange.

    Vonwegen langsam - Exceptions sollten nicht verwendet werden um flow control zu machen, wenn etwas häufig vorkommt - wie du auch schon richtig festgestellt hast. Und dann ist es auch "ziemlich egal" wie lange es dauert, solange eben keine fliegen.

    Was die "immer mehr try Blöcke" angeht - ich bin eigentlich gegen viel try Blöcke. "Guards" sind viel besser 🙂 Viele try Blöcke sind IMHO ein Zeichen von schlechtem Design, oder davon dass jmd. nicht verstanden hat wie man Exceptions sinnvoll einsetzen kann.

    Errorhandling ist aber so oder so (mit oder ohne Exceptions) ein schwieriges Thema. Auf jeden Fall bin ich der Meinung dass man innerhalb von einem Programm nicht mischen sollte. Jack. Pfui. Funktionen/Methoden die im Fehlerfall entweder mit einem Errorcode oder aber einer Exception zurückkommen sind fürchterlich.



  • hustbaer schrieb:

    @Xin:
    Das Suchen in den Tabellen, die, wie du richtig sagst, recht gross werden können, wird nicht notwendigerweise langsam, wenn die Datenstruktur in der man diese Tabellen ablegt entsprechend ist (Baum, Skip-List, wo's Sinn macht evtl. nen Hash etc.). Und dass die Tabellen gross werden ist wirklich nur dann von Bedeutung wenn man wenig Speicher hat - die müssen ja nicht bei Programmstart gleich vollständig in den Speicher geladen werden - von daher dauert das auch nicht so schlimm lange.

    Dann müssten sie nachgeladen werden, was kostenmäßig den Super-GAU darstellt.

    hustbaer schrieb:

    Vonwegen langsam - Exceptions sollten nicht verwendet werden um flow control zu machen, wenn etwas häufig vorkommt - wie du auch schon richtig festgestellt hast. Und dann ist es auch "ziemlich egal" wie lange es dauert, solange eben keine fliegen.

    Falsch - oder zumindest zu kurz gedacht.

    Wenn Exceptions fliegen könnten, dann muss für jede Exception geprüft werden, ob sie jetzt geworfen werden soll oder ob doch alles im so läuft, wie man sich das vorstellt.
    Je tiefer die Prüfungen stattfinden, desto häufiger finden sie statt. Lasst man den Algorithmus laufen und guckt nur an den Stellen, an denen der Algorithmus falsche Werte liefern kann, ob es falsche Werte gibt, dann wäre das schneller.

    Ein Beispiel wäre eine Exception für eine Wurzelfunktion, die prüft, ob die Wurzel aus negativen Werten gezogen werden soll.
    Bildet man das Skalarprodukt, wird sich niemals ein negativer Wert einfinden, die Prüfung, ob man jetzt eine Exception wegen einer negativen Eingabe machen muss, hält also nur auf.

    Auch das sind Kosten, die auf Exceptionhandling zurückgehen.

    hustbaer schrieb:

    Was die "immer mehr try Blöcke" angeht - ich bin eigentlich gegen viel try Blöcke. "Guards" sind viel besser 🙂 Viele try Blöcke sind IMHO ein Zeichen von schlechtem Design, oder davon dass jmd. nicht verstanden hat wie man Exceptions sinnvoll einsetzen kann.

    Hier sind wir absolut einer Meinung.

    Allerdings sehe ich die Möglichkeit der Exceptions durchaus als Vorteil an. Es gibt auch gute Gründe für Exceptions, aber viel weniger, als Exceptions benutzt werden.
    Exceptions sind eben keine zusätzliche Möglichkeit eines Rückgabewertes, wie es offenbar gelegentlich verstanden wird.



  • Xin schrieb:

    Falsch - oder zumindest zu kurz gedacht.

    Wenn Exceptions fliegen könnten, dann muss für jede Exception geprüft werden, ob sie jetzt geworfen werden soll oder ob doch alles im so läuft, wie man sich das vorstellt.
    Je tiefer die Prüfungen stattfinden, desto häufiger finden sie statt. Lasst man den Algorithmus laufen und guckt nur an den Stellen, an denen der Algorithmus falsche Werte liefern kann, ob es falsche Werte gibt, dann wäre das schneller.

    Ein Beispiel wäre eine Exception für eine Wurzelfunktion, die prüft, ob die Wurzel aus negativen Werten gezogen werden soll.
    Bildet man das Skalarprodukt, wird sich niemals ein negativer Wert einfinden, die Prüfung, ob man jetzt eine Exception wegen einer negativen Eingabe machen muss, hält also nur auf.

    Auch das sind Kosten, die auf Exceptionhandling zurückgehen.

    Äh, nein. Ich denke es macht keinen Sinn "exceptions" mit "garkein error handling" zu vergleichen, dann wird was geschwindigkeit angeht immer "garkein error handling" gewinnen, das ist klar.

    Aber vergleich mal error handling über exceptions mit error handling über return codes. Wobei die Prüfung "ist fehler?" natürlich an den gleichen Stellen zu passieren hat. Dann siehts die Sache nämlich schon wieder ganz anders aus. Dann muss nämlich nicht nur auf unterster Ebene 1x geprüft werden, sondern auf allen Schichten dazwischen nochmal. Jack. Pfui.



  • hustbaer schrieb:

    Äh, nein. Ich denke es macht keinen Sinn "exceptions" mit "garkein error handling" zu vergleichen, dann wird was geschwindigkeit angeht immer "garkein error handling" gewinnen, das ist klar.

    Aber vergleich mal error handling über exceptions mit error handling über return codes. Wobei die Prüfung "ist fehler?" natürlich an den gleichen Stellen zu passieren hat. Dann siehts die Sache nämlich schon wieder ganz anders aus. Dann muss nämlich nicht nur auf unterster Ebene 1x geprüft werden, sondern auf allen Schichten dazwischen nochmal. Jack. Pfui.

    Ich denke, hier prallen zwei Philosophien aufeinander.

    Wann immer möglich, möchte ich kontrollierte Daten in meinem Programm haben.
    Das heißt, dass ich mir vorher überlege, was erlaubt ist - und was nicht, also dafür sorge, dass keine unkontrollierten Daten in meine Algorithmen kommen.

    Dann schreibe ich Algorithmen, die unter den notwendigen Bedingungen funktionieren - ohne irgendeine Kontrolle, ob die Daten mit denen sie gefüttert werden einen Sinn ergeben. Das habe ich ja bereits vorher getan. Das heißt, mir ist egal, was die Funktionen ausgeben, wenn sie mit unsinnigen Werten gefüttert werden. Wer dumme Fragen stellt, bekommt dumme Antworten.

    Ich sorge auf möglichst hoher Ebene, dass keine Dummen fragen gestellt werden.
    Dadrunter benötige ich keine Fehlerbehandlung mehr.

    Mich persönlich stört es überhaupt nicht, ob ein Programm eine Aufgabe nicht lösen kann, weil es abschmiert oder ob es eine Aufgabe nicht lösen kann, weil es eine Exception wirft und abbricht.

    Bug ist Bug.

    Wenn das Exceptionhandling dazu führt, das ich noch eine Meldung bekomme wie 'Unerwarteter Fehler', dann frage ich mich, wieso der Fehler doch immerhin so erwartet kam, dass man es geschafft hat eine Message-Box dazu zu programmieren. Irgendwie komme ich mir als User da ein wenig veräppelt vor.

    Programme, die mit Hilfe von Exceptions wieder in einen funktionsfähigen Zustand gebracht werden, also die Aufgabe dann tatsächlich ohne Neustart lösen können sind wohl eher eine Exception.
    Und genau da sehe ich die Aufgabe von Exceptions.
    Die Ampelsteuerung schmiert ab, Exception, erstmal alles anhalten und sicherstellen, dass die Kreuzung frei ist, dann Techniker informieren, dann in aller Ruhe ganz von vorne anfangen, notfalls Warnlicht. Das ist in meinen Augen eine Anwendung, für die sich Exceptions hervorragend eignen.



  • Neh, da prallen keine zwei Philosophien aufeinander. Ich rede von Laufzeitfehlern. Exceptions sollten für Laufzeitfehler verwendet werden. Jeder Zugriff auf die Hardware z.B. kann daneben gehen, und ich möchte nicht dass mein Programm einfach so ohne Meldung abschmiert weil das Diskettenlaufwerk am sterben ist oder ein File nicht gefunden wurde etc.

    Mich persönlich stört es überhaupt nicht, ob ein Programm eine Aufgabe nicht lösen kann, weil es abschmiert oder ob es eine Aufgabe nicht lösen kann, weil es eine Exception wirft und abbricht.

    Bug ist Bug.

    Mich würde es doch sehr stören wenn ein Programm einfach 42 als Lösung ausspuckt, ohne Fehlermeldung, als ob alles glatt gegangen wäre, wenn doch die richtige Lösung 100 ist. Als Beispiel. Ohne error checking kann dir genau das passieren. Weiss nicht ob das so toll ist.



  • hustbaer schrieb:

    Neh, da prallen keine zwei Philosophien aufeinander. Ich rede von Laufzeitfehlern. Exceptions sollten für Laufzeitfehler verwendet werden. Jeder Zugriff auf die Hardware z.B. kann daneben gehen, und ich möchte nicht dass mein Programm einfach so ohne Meldung abschmiert weil das Diskettenlaufwerk am sterben ist oder ein File nicht gefunden wurde etc.

    Lies mein vorheriges Posting nochmal. Daten in einem gültigen Format vorliegen haben, dann keine überflüssigen Abfragen mehr.
    Daten, die ich nicht vorliegen habe, ... da brauche ich mir auch keine Gedanken machen, ob die gültig sein könnten.

    Weiterhin ist das Nicht-Auffinden von Daten keine derartige Besonderheit, dass es eine Exception erfordern würde.
    Eine Exception könnte ich akzeptieren, wenn das Laufwerk während des Lesens verschwindet, weil jemand über das USB-Kabel gestolpert oder das Netzwerk zusammengebrochen ist.

    Wenn man Exceptions vermeidet, heißt das schließlich nicht, dass es kein Error-Handling gibt.
    Genauso werden Usereingaben geprüft - bevor sie in einen Algorithmus wandern. Der Algorithmus wird mit falschen Werten gar nicht erst belastet.

    hustbaer schrieb:

    Mich würde es doch sehr stören wenn ein Programm einfach 42 als Lösung ausspuckt, ohne Fehlermeldung, als ob alles glatt gegangen wäre, wenn doch die richtige Lösung 100 ist. Als Beispiel. Ohne error checking kann dir genau das passieren. Weiss nicht ob das so toll ist.

    Das kann Dir mit Prüfungen genauso passieren. Fehlerhafte Algorithmen werden nicht besser, wenn sie durch dauernde Prüfungen verlangsamt werden.
    Daten, die ungültig sind und das Ergebnis verfälschen, werden vorher abgefangen. Da ist das Error-Checking.
    Kompliziertere Alrithmen müssen in ihren möglichen Wegen getestet werden. Welche Eingaben sind möglich, wieviele Fälle treten auf, ist für jeden Fall ein Testfall mit bekannter Lösung vorhanden?

    Dann wird mit den Daten gerechnet - ohne Error-Checking. Kommt dann 42 statt 100 raus, hat das Programm einen Bug. Da helfen auch Prüfungen nichts mehr. Das kann Dir genauso gut mit 20000 zusätzlichen Abfragen passieren. Ein paar Asserts beim Testen gerne. Aber wenn das Programm ausgeliefert wird, ist es entweder korrekt - oder buggy.
    Mit oder ohne Abfragen.

    Ich habe auch nichts gegen Abfragen, im Algorithmus - wenn sie notwendig sind.
    Aber die berühmte Wurzel, die prüft ob der Parameter negativ ist, interessiert mich nicht.
    Wenn ich z.B. eine Vektorlänge berechne ist es absolut unmöglich, dass ich aus einer negativen Zahl die Wurzel ziehe. Berechne ich ein paar Millionen Vektoren, sind das ein paar Millionen überflüssiger Abfragen. Ich will nicht, dass sqrt() meine Eingabe prüft in Fällen, wo dies nicht nötig ist.

    Wenn mein Algorithmus negative Zahlen ausspucken kann und diese Zahlen sqrt() übergibt, dann ist mein Algorithmus dafür verantwortlich, wenn da Müll rauskommt - nicht sqrt().
    Dann muss mein Algorithmus an dieser das prüfen und gegebenfalls die Information zurückliefern, wenn was schlief läuft. Dafür habe ich mir vorher Gedanken gemacht, welche Wege meine Funktion gehen kann und in welchem Wertebereichen sich die Variablen befinden können.
    Aber eine Abfrage an der richtigen Stelle reicht, das muss nicht in jeder Funktion geprüft werden.

    Das kann man als Entwickler gerne mit einer speziellen Debug-Version der entsprechenden Libs prüfen, aber der fertige Algorithmus darf keine Sicherheitsleinen mehr brauchen, sondern garantiert in exakt definierten Bahnen verlaufen.


Anmelden zum Antworten