Meinungsfrage zu Exceptions



  • knivil schrieb:

    Hey, welcome in exception hell. Sehe ich das richtig, dass du mehr Klassen fuer Exception hast, als "normale" Klassen?

    Ähm ja, zzt kommen 12 Klassen die bereits schon Exceptions haben auf 24 Excepions (Basisklassen inklusive). Dabei soltle ich aber auch erwähnen das ich keine Exception wiederverwende, dh jede Klasse die inetrn new benutzt oder eine DX Komponente die OutOfMemory werfen kann ihre eigene OutOfMemory Exception hat, dh die kommen in dem Exception baum mehrfach vor.

    knivil schrieb:

    Btw. Exceptions sollten nicht als Debuggingersatz herhalten. Du kannst auch einfach eine Exceptionklasse fuer fatal errors nutzen und in what() "reinschreiben", was schiefgegangen ist. Recovering von out_of_memory kannste ja eh nicht.

    Ja ich benutze sie auch nichtd afür ich teile fehelr mit die durch Debuggen nicht lösbar sind, also zB nicht gefundene Daten oder Dateien, fehler beim holen von Speicher, usw. um what() zu haben muß man dafür seine Exceptions nicht von der Exceptionklasse aus der std ableiten?



  • Dein Fehler ist, dass du die Fehler nicht generalisierst.

    NotAvailable ist kein Fehler des Texturmanagers sondern generell eine nicht vorhandene Resource. OutOfMemory ist ebenfalls ein genereller Fehler und nicht Teil einer Klasse.

    Du hast also folgende Struktur:

    Error
    - MemoryError
    - - OutOfRam
    - - OutOfVRam
    - InvalidOperationError
    - - InvalidCall
    - - InvalidData
    - - InvalidState

    Und mit diesen Exceptions arbeitest du im ganzen Programm. Es ist egal wer den InvalidCall verursacht hat (ob der Texturmanager oder der ObjektManager oder sonstwer) - das ist nur dann direkt beim behandeln des fehlers interessant (wenn überhaupt).



  • Der Ansatz, dass verschiedene Klassen auch verschiedene Exceptions haben ist überflüssig. Der Grund ist folgender:
    Im Idealfall kannst du eine Exception nahe der Stelle fangen (und behandeln) wo sie auftritt. Das bedeutet aber, dass du weißt, ob sie jetzt aus einer Methode von Foo oder aus einer Methode von Bar kommt, weil der try-Block vermutlich nur eine solche Methode umschließt. In dem Fall machts also schonmal keinen Sinn, zwischen einer Bar_Bad_Dingsbums_Exception und einer Foo_Bad_Dingsbums_Exception zu unterscheiden.
    Im weniger günstigen Fall kannst du eine Exception nicht direkt behandeln sondern lässt sie durchrauschen (oder wandelst sie um). Weiter entfernt von dem eigentlichen Problem kannst du aber nicht das eigentliche Problem selbst behandeln (eben deshalb behandelst du sie ja erst weiter weg von ihrem Ursprung). Das bedeutet, du musst "weit im Gesunden abschneiden" - also den ganzen Foo-Bar-Komplex in die Tonne treten und was anderes versuchen. In dem Fall ist es also auch egal ob die Exception aus Foo oder aus Bar kommt, weils keinen Unterschied macht warum du alles wegwerfen musst.



  • Ja da habt ihr natürlich Recht vond er Seite aus hab ich das nie gesehen, und für den Herkunftsort würde ja zur Not auch ein Flag reichen das die Klasse angibt wo der Fehler herstammt. Die Variante von Shade gefällt mir auch bedeutend besser als meine, sie ist eindeutig sehr viel übersichtlicher als meine, vor allem wenn ich bedenke wieviele Exceptions mir noch fehlen würde umd as Konzept zu einem Ende zu bringen.



  • Ich nutze den Thread mal noch für ne Frage in die Runde.

    Ich hab mir gestern mal die Implementierung von Exception und what() angeschaut. Dabei ist mir aufgefallen das für die Nachricht die versendet wird extra Speicher angelegt wird, zwar mit malloc aber das is ja egal, daher mal meine Frage, angenommen new schlägt fehl und ich kann OutOfMemory werfen, gäbe es dann eine Garantie das ich Speicherplatz in der Exception für die Nachricht bekomme? also wird von vornherein ein Gewisser Speicher für Exceptions Reserviert um zu Garantieren das da nichts schiefgeht? Wenn nicht könnte ja Theoretisch der Konstruktor der Exception wenn man New Benutzt auch ne Exception werfen.



  • Xebov schrieb:

    Dabei ist mir aufgefallen das für die Nachricht die versendet wird extra Speicher angelegt wird, zwar mit malloc aber das is ja egal, daher mal meine Frage, angenommen new schlägt fehl und ich kann OutOfMemory werfen, gäbe es dann eine Garantie das ich Speicherplatz in der Exception für die Nachricht bekomme?

    Wenn auf einem modernen OS eine out of memory exception fliegt, dann bist du eh schon tot. Denn OOM geht ein system nur, wenn wirklich alles komplett voll ist. meistens ist es sogar so, dass new garnicht bad_alloc werfen kann, da das system meistens mit einem lazy commit arbeitet und so prinzipiell immer behauptet speicher zu haben.

    bei out of memory also am besten die anwendung beenden. (wenn das denn überhaupt machbar ist). ich fange bad_alloc zB explizit nicht ab und sterbe lieber als mich mit dem fall auseinander zu setzen 😉



  • Shade Of Mine schrieb:

    Wenn auf einem modernen OS eine out of memory exception fliegt, dann bist du eh schon tot. Denn OOM geht ein system nur, wenn wirklich alles komplett voll ist. meistens ist es sogar so, dass new garnicht bad_alloc werfen kann, da das system meistens mit einem lazy commit arbeitet und so prinzipiell immer behauptet speicher zu haben.

    bei out of memory also am besten die anwendung beenden. (wenn das denn überhaupt machbar ist). ich fange bad_alloc zB explizit nicht ab und sterbe lieber als mich mit dem fall auseinander zu setzen 😉

    Das heist also es wäre bad_alloc aber das bad_alloc bleibt irgendwo stecken. Gut zu wissen. Ich fange sie zzt ab und wandel sie um um einige Zeiger aufzuräumen die sonst als Speicherleck verschwinden würden. Aber danke für die Antwort dann kann ich ja beruhigt weiter dran rum basteln.


  • Administrator

    Xebov schrieb:

    Ich fange sie zzt ab und wandel sie um um einige Zeiger aufzuräumen die sonst als Speicherleck verschwinden würden. Aber danke für die Antwort dann kann ich ja beruhigt weiter dran rum basteln.

    !! RAII !!
    😃

    Du musst die Dinger nicht abfangen um aufzuräumen, wenn du dein Programm richtig aufgebaut hast, dann reichen die Destruktoren, welche automatisch aufgerufen werden 😉

    Übrigens, ein bad_alloc heisst nicht immer, dass der Speicher unbedingt voll ist. Es kann auch sein, dass zum Beispiel nicht die Menge Speicher, welche angefordert wurde, an einem Stück zu finden war. Kleinere Stücke können dann womöglich angelegt werden und wenn man ein paar Ebenen raufgeht, dann ist auch wieder Speicher vorhanden, meistens.

    Allerdings fange ich "Out Of Memory" und co eigentlich auch so gut wie nie ab. Hat meistens keinen Sinn.

    Grüssli



  • Dravere schrieb:

    !! RAII !!
    😃

    Du musst die Dinger nicht abfangen um aufzuräumen, wenn du dein Programm richtig aufgebaut hast, dann reichen die Destruktoren, welche automatisch aufgerufen werden 😉

    Ja ich verlasse mich aucb auf RAII abe rnicht immer, wenn ich zB eine temporäre Variable brauche erstelel ich die eben mit new und die muß ja dann auch gelöscht werden. Den ganzen Rest überlasse ich zum großteils chon RAII.

    Dravere schrieb:

    Übrigens, ein bad_alloc heisst nicht immer, dass der Speicher unbedingt voll ist. Es kann auch sein, dass zum Beispiel nicht die Menge Speicher, welche angefordert wurde, an einem Stück zu finden war. Kleinere Stücke können dann womöglich angelegt werden und wenn man ein paar Ebenen raufgeht, dann ist auch wieder Speicher vorhanden, meistens.

    Allerdings fange ich "Out Of Memory" und co eigentlich auch so gut wie nie ab. Hat meistens keinen Sinn.

    Naja ob der Speicher voll ist oder nur das Stück in der Größe nicht vorhanden ist ist ansich ja eh egal, das Objekt kann so und so auch nicht angelegt werden.

    Ich mache damit im Grunde auch nichts weiter ich nutze sie halt zum Aufräumen oder um zu verhindern das Daten ungültig werden. Also um in Klassen zum Beispiel Änderungen rückgängig zu machen die vor der Exception gemacht wurden, das gilt aber bei mir für alle Exceptions.

    Danke auf jedenfall für die Ausführliche Auskunft.


  • Administrator

    Xebov schrieb:

    Ja ich verlasse mich aucb auf RAII abe rnicht immer, wenn ich zB eine temporäre Variable brauche erstelel ich die eben mit new und die muß ja dann auch gelöscht werden. Den ganzen Rest überlasse ich zum großteils chon RAII.

    Für sowas gibt es Smart Pointer, bzw. der Scoped Pointer oder aktuell in der Standardbibliothek der auto_ptr:
    http://www.cplusplus.com/reference/std/memory/auto_ptr/

    void foo()
    {
      // Objekt temporär auf dem Heap anlegen:
      std::auto_ptr<BigObject> bigObjectPtr(new BigObject());
    
      bigObjectPtr->do_something();
    
      bar(bigObjectPtr);
    
      // usw.
    }
    
    // Speicher wird von std::auto_ptr automatisch freigegeben.
    

    Für die Smart Pointer empfiehlt es sich, mal bei Boost vorbeizuschauen:
    http://www.boost.org/doc/libs/1_38_0/libs/smart_ptr/smart_ptr.htm

    Grüssli



  • Xebov schrieb:

    Nachdem letztens der Thread oben war über Fehlerbehandlung in Engines bei dem einige Interessante Aspekte angesprochen wurden

    Kann mir bitte mal jemand den Link zu dem Thread geben ich finde ihn net. 😞





  • Jap das war der.

    Danke Dravere ich werd mir das mal ansehen mit dem Boost mal sehen inwiefern sich das ganze eigent und wie das überhaupt funktioniert.


Anmelden zum Antworten