Fehlerbehandlung in einer Engine
-
knivil schrieb:
alloc10resources { 10 Lokale Objekte; b = true; b = b && alloc( Resource1 ) b = b && alloc( Resource2 ) ... if( b ) copy resources or whatever smart_ptr }
Z.B. so?
Und woher weisst Du, bei welchem alloc das ganze daneben ging?
-
Shade Of Mine schrieb:
...Ja, es kostet mehr Code. Aber statt einem throw machst du halt return.
Okay, das geht natürlich. Wobei man bei da bei Konstruktoren auf Fehlerinformationen verzichen muss.
-
Ist doch egal. Resourcendestruktor kuemmert sich um die korrekte Freigabe, RAII halt. Kannst auch wahlweise im Log nachsehen. alloc10res kann einfach b zurueckliefern.
-
knivil schrieb:
Ist doch egal. Resourcendestruktor kuemmert sich um die korrekte Freigabe. Kannst auch wahlweise im Log nachsehen.
Problem ist aber, woher weiss die ressource dass sie sich zerstören muss?
Wenn ich ein LoadAllModels() mache - und beim 7. sterbe ich - woher wissen die anderen 6 dass sie ebenfalls sterben müssen?
für sowas hat man denn etwas ähnliches wie mein DelayedRangeExecute (im prinzip also einen ScopeGuard) - aber ich habe das gefühl ich greife etwas zu weit voraus
Schau dir aber mal meinen Code an - und vergleiche die exception und die return code variante. Welche ist besser?
Der Punkt ist:
du hast mit exceptions weniger code zu schreiben und verwässerst dir den code nicht mit fehlerbehandlung. nebenbei sind dann noch so ein paar sachen nett ala schutz vor murphy - wenn du mal vergisst auf einen fehler zu reagieren, etc.
-
Die Ressource weiss, das sie geladen wurde oder nicht geldaen wurde. Ist 'nen Objekt und zustandsbehaftet. Sie weiss es einfach. Z.B. bool Texture.load(...) legt Speicher an kopiert Texturdaten rein. Naja, ist was fehlgeschlagen, dann ist der Speicherpointer halt 0. Lade ich jetzt meine 10 Texturen wird nur im Erfolgsfall kopiert, smart_ptr whatever ... . Falls nicht, wird der Destruktor der Resourcen aufgerufen.
Btw. ich weiss schon was es mit RAII, Gards etc. auf sich hat. Aber es ging ja um Exceptions. Wenn bool Texture.load( ... ) 'ne Exception werfen wuerde, dann waere ich gezwungen mittels try-catch diese zu fangen. Hier gebe ich einfach nur false zurueck. Soll der Benutzer der Funktion sich darum kuemmern. (Nein es ist nicht der Anwender, sondern der Programmierer, der meine Funktion benutzt, meist ich selber).
-
knivil schrieb:
Die Ressource weiss, das sie geladen wurde oder nicht geldaen wurde. Ist 'nen Objekt und zustandsbehaftet. Sie weiss es einfach. Z.B. bool Texture.load(...) legt Speicher an kopiert Texturdaten rein. Naja, ist was fehlgeschlagen, dann ist der Speicherpointer halt 0. Lade ich jetzt meine 10 Texturen wird nur im Erfolgsfall kopiert, smart_ptr whatever ... . Falls nicht, wird der Destruktor der Resourcen aufgerufen.
Und wer ruft den Destruktor in welchem Fall auf, und wie stellst Du sicher, dass die Destruktoren im Erfolgsfall nicht beim Verlassen des Scopes aufgerufen würden, was Deine Smartpointer invalidieren würde?
knivil schrieb:
...Soll der Benutzer der Funktion sich darum kuemmern. (Nein es ist nicht der Anwender, sondern der Programmierer, der meine Funktion benutzt, meist ich selber).
Verstehe ich nicht. Wo ist der Unterschied zu Exceptions? Da kannst Du auch sagen, "soll sich der Benutzer drum kümmern". Du musst die Exception nicht fangen. Du musst Ihm nur sagen, dass eine bestimtme Exception geworfen werden kann, genauso wie Du Ihm sagen musst was es bedeutet, wenn Deine Funktion false zurückgibt.
-
Hui, da habe ich ja ganz schön was losgetreten
Naja, jetzt kann ich mich auf jedenfall nicht beklagen, dass ich zu wenig Rückmeldungen hatte und das Thema nicht genug diskutiert wurde :).
MfG
HundefutterP.S.: Diskutiert noch schön weiter, ist sehr interessant, aber bitte lasst alle am Leben
-
Verstehe ich nicht. Wo ist der Unterschied zu Exceptions?
q.e.d
-
knivil schrieb:
Die Ressource weiss, das sie geladen wurde oder nicht geldaen wurde. Ist 'nen Objekt und zustandsbehaftet. Sie weiss es einfach. Z.B. bool Texture.load(...) legt Speicher an kopiert Texturdaten rein. Naja, ist was fehlgeschlagen, dann ist der Speicherpointer halt 0. Lade ich jetzt meine 10 Texturen wird nur im Erfolgsfall kopiert, smart_ptr whatever ... . Falls nicht, wird der Destruktor der Resourcen aufgerufen.
Aufpassen.
Es geht darum WANN der Dtor aufgerufen werden soll. Und das muss er manchmal eben sofort (rollback) und nicht später.Btw. ich weiss schon was es mit RAII, Gards etc. auf sich hat. Aber es ging ja um Exceptions. Wenn bool Texture.load( ... ) 'ne Exception werfen wuerde, dann waere ich gezwungen mittels try-catch diese zu fangen. Hier gebe ich einfach nur false zurueck. Soll der Benutzer der Funktion sich darum kuemmern. (Nein es ist nicht der Anwender, sondern der Programmierer, der meine Funktion benutzt, meist ich selber).
Nein. exceptionsicherheit hat nichts aber auch rein garnichts mit try/catch zu tun.
Schau dir mal die codes in meinem artikel an - wieviele try/catch siehst du? Im idealfall hast du exakt 1 try/catch in deinem programm.
-
Ich kenne den Unterschied zwischen exceptionsicher und und Exceptions. Aber ich sollte doch ein Beispiel fuer 10 Resourcen ohne Verwendung von Exceptions fuer Tachyon liefern ... dat isses. Ja wenn sofort ein Rollback durchgefuehrt werden soll, dann ... muss ich drueber nachdenken. In dem Artikel kommen sehr wenig try/catch vor, aber ich bin da noch von dem anderen Artikel gepraegt ...
Verstehe ich nicht. Wo ist der Unterschied zu Exceptions?
Ich benutze keine und zwinge den Benutzer/Programmierer nicht dazu, welche zu benutzen. Wenn er dann eine Exception basierend auf der Rueckgabe werfen moechte, kann er gern machen.
-
knivil schrieb:
Aber ich sollte doch ein Beispiel fuer 10 Resourcen ohne Verwendung von Exceptions fuer Tachyon liefern ...
Dein Beispiel funktioniert aber nicht, bzw. macht keinen Sinn.
-
knivil schrieb:
aber ich bin da noch von dem anderen Artikel gepraegt ...
Dann wird es Zeit dass du dir modernes Exceptionhandling ansiehst und mir Gründe nennst warum error Codes besser sind.
Vorallem solltest du mal darüber meditieren:
Es gibt 3 Probleme mit diesem Code.
- Die Fehlerbehandlung erfolgt lokal und macht dadurch den Code schwerer lesbar.
- Jede Funktion verlangt andere Behandlung von Fehlern.
- In Sprachen ohne Garbage-Collector muss man seinen eigenen Mist selbst wegräumen. Dieser Cleanup-Code ist kompliziert einzubauen. Hier z.B. über hässliche gotos gelöst. Alternativ auch mit tief verschachtelten ifs lösba
Punkt 3 ist mit RAII lösbar, aber Punkt 1 und 2 liegen schwer.
-
What the fuck ? So (aehnlich) arbeite ich staendig. Ich muss zugeben, dass ich mir nicht die Muehe gemacht habe ein schoen formatiertes Beispiel mit C++ Syntax zu basteln. Sorry.
Error Codes besser/schlechter ... das ist so eine Ansichtssache. Ich finde Exceptions restriktiver. Mom, ich suche mal nen Zitat ... finde es grad nicht, sorry
-
knivil schrieb:
Ich finde Exceptions restriktiver
Gründe bitte.
-
Ich zwinge den Benutzer meiner Funktion auch Exceptions zu benutzen. Er kann nicht auf Exceptions verzichten.
-
knivil schrieb:
Ich zwinge den Benutzer meiner Funktion auch Exceptions zu benutzen. Er kann nicht auf Exceptions verzichten.
Und die Alternative: Erzwingen lokaler Fehlerbehandlung durch das Verwenden von Error-Codes findest du weniger restriktiv?
-
Helferlein, Ein schrieb:
knivil schrieb:
Ich zwinge den Benutzer meiner Funktion auch Exceptions zu benutzen. Er kann nicht auf Exceptions verzichten.
Und die Alternative: Erzwingen lokaler Fehlerbehandlung durch das Verwenden von Error-Codes findest du weniger restriktiv?
knivil, dabei könntest du es dir doch so einfach machen. Es gibt nämlich ein Argument gegen Exceptions und für Error-Codes. Ich gehe soweit und sage sogar es ist das Argument gegen Exceptions.
-
knivil schrieb:
Ich zwinge den Benutzer meiner Funktion auch Exceptions zu benutzen. Er kann nicht auf Exceptions verzichten.
Genauso zwingst du den Benutzer deiner Funktion lokal auf die Fehler zu reagieren. Er kann nicht auf error codes verzichten.
Deshalb: sag mal n ordentliches argument gegen exceptions
-
Helferlein, Ein schrieb:
Und die Alternative: Erzwingen lokaler Fehlerbehandlung durch das Verwenden von Error-Codes findest du weniger restriktiv?
Soll er doch ne Exception werfen basierend auf den Fehlercode. Prinzipiell habe ich nichts gegen Exceptions, nur werden sie haeufig an falscher Stelle eingesetzt.
Ich soll 's mir so einfach machen? Hoert auf mich zu noetigen und Generalisieren werde ich nicht! Exceptions ueber Bibliotheksgrenzen hinweg sind einfach scheisse und alles was damit zusammenhaengt. Aber das 'nen generelles Problem von C++.
-
Da is man mal ne Studne nicht da und hat gleich richtig was zu lesen.
Shade Of Mine schrieb:
if(!InitDevice()) { return ID_FAILED; } if(!SetupScene()) { return SS_FAILED; } if(!RunLoop()) { return RL_FAILED; }
versus
InitDevice(); SetupScene(); RunLoop();
Ich habe jetzt mal den Code zusammenkopiert. Zum oberen Teil, was wäre dann dem If so evrwerflich? man sieht auf einen Blick was Sache ist und was passiertw enn was passiert, option nr2 ohne die Ifs steht einem ja auch noch offen wenn man sich 100% sicher ist das es so klappen kann.
Shade Of Mine schrieb:
class Class { private: char* name; int* array; public: Class(char const* name) : name(0), array(0) { try { this->name = new char[strlen(name)+1]; array = new int[100]; } catch(std::bad_alloc& e) { delete [] this->name; delete [] array; throw; } strcpy(this->name, name); fill(array); } //... };
Alternativ auch mit if/else und 0 statt bad_alloc vorstellbar.
Aber dank exceptions kann ich daraus folgendes machen:
class Class { private: std::string name; std::vector<int> array; public: Class(char const* name) : name(name), array(100) { fill(array); } //... };
Ja sowas im drehe meine ich das hab ich gelesen. Was ich an dem Beispiel auszusetzen hätte wäre das man das selbe was da ind em Try Block und dem Katch passiert auch über ne einafche if Abfrage lösen könnte, ich meine es klappt doer nicht und die Variante if und errorcode würde das selbe bewirken, der Anwender könnte ja genauso abfragen obe r errrorcode geliefert wurde und dann an eine Funktion verweisen die das Problem beseitigt, damit wäre dann die Fehlerbehandlung auch ausgelagert. Teil 2 erschließt sich mir nicht wo sind denn da die Exceptions?
Mir fehlt nachwievor ein guter Grund die sachen einzusetzen, ich habe hier zB gerade ein Gedankenspiel, ich habe einen Texturmanager der Texturen lädt und verwaltet. Wenn eine Textur nicht geladen werden kann kann ich genauso einen errorcode abgeben der sagt das teil kontne nicht geladen werden, was der Nutzer damit macht wäre ja egal, ich sehe da in Exceptions keinen Vorteil, nur den Nschteil das ich sie nicht ignorieren darf. Eine Ordliche fehlerbehandlung müsste ich auch nichtmal durchführen, denn in dem Moment wo mir ein Errorcode entgegen komtm kann ich genauso auf eine Funktion verweisen die zB eine Standarttextur lädt die für diesen Fall vorgesehen ist, das geht mit Exceptions genauso, sie liefern mir also Gedanklich keinen vorteil, nur Nachteile weil ich die Ifs bedeutend Lesbarer finde.