Exception Frage
-
Ich habe 2 Fragen zu Exceptions. Folgende Funktion:
bool Renderer::createDevice(bool debugDevice, IDXGIAdapter* adapter) { IDXGIFactory* factory = NULL; if( FAILED(CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast<void**>(&factory))) ) { SAFE_RELEASE(factory); return false; } if( FAILED(D3D10CreateDevice(adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, debugDevice ? D3D10_CREATE_DEVICE_DEBUG : 0, D3D10_SDK_VERSION, &device)) ) { SAFE_RELEASE(factory); return false; } SAFE_RELEASE(factory); return true; }Die Funktion kann an mehreren Stellen (beim Aufruf der DirectX Funktionen CreateDXGIFactory() und D3D10CreateDevice()) versagen. Meine Frage ist nun: Sollte ich lieber wie jetzt den Erfolg/Misserfolg der Funktion mit einem bool liefern, oder beim Versagen eine Exception werfen (sprich: statt "return false" ein "throw DXCallException("bla")"? Einerseits ist ein Versagen der DirectX Funktion etwas normales, andererseits wären Exceptions irgendwie eleganter.
Meine Frage: Ich benutze in meinem Programm Logging. Sollte der Constructor meiner Exceptionklasse automatisch einen Log Eintrag anlegen?
-
Exception werfen: Ja.
Logging gleich in der Exception Klasse: Nein. Du machst einen Eintrag ins Logbuch frühestens dort wo du den Fehler behandelst.Ich möchte zudem noch auf die folgenden 3 Artikel verweisen:
Exception Handling
Modernes Exception Handling Teil 1
Modernes Exception Handling Teil 2Grüssli
-
Dravere schrieb:
Logging gleich in der Exception Klasse: Nein. Du machst einen Eintrag ins Logbuch frühestens dort wo du den Fehler behandelst.
Nun ja, aber ich schreibe an einer Engine (der Code da oben gehört dazu) und die wird dann in eine .lib kompiliert. Da wäre es dann doch vorteilhaft, wenn die Engine interne Fehler mitloggt.
-
eulentier schrieb:
Dravere schrieb:
Logging gleich in der Exception Klasse: Nein. Du machst einen Eintrag ins Logbuch frühestens dort wo du den Fehler behandelst.
Nun ja, aber ich schreibe an einer Engine (der Code da oben gehört dazu) und die wird dann in eine .lib kompiliert. Da wäre es dann doch vorteilhaft, wenn die Engine interne Fehler mitloggt.
Im Debug-Mode durchaus sinnvoll, aber spätestens im Release-Mode würde ich diese Log deaktivieren (oder evtl dem Nutzer die Möglichkeit geben, selbst zu bestimmen, ab welchem Logging-Level geloggt werden soll).
Aber eigtl seh ich das genau so wie Dravere - entweder, der Fehler wird gefangen und der Nutzer der lib loggt diesen irgendwie oder er wird gefangen und verworfen oder er wird nicht gefangen - im zweiten Fall ist ihm der Fehler offensichtlich egal und im dritten Fall will er sie nicht fangen oder die Doku ist zu schlecht bzw er ist zu faul, diese zu lesen...
bb
-
unskilled schrieb:
eulentier schrieb:
Dravere schrieb:
Logging gleich in der Exception Klasse: Nein. Du machst einen Eintrag ins Logbuch frühestens dort wo du den Fehler behandelst.
Nun ja, aber ich schreibe an einer Engine (der Code da oben gehört dazu) und die wird dann in eine .lib kompiliert. Da wäre es dann doch vorteilhaft, wenn die Engine interne Fehler mitloggt.
Im Debug-Mode durchaus sinnvoll, aber spätestens im Release-Mode würde ich diese Log deaktivieren (oder evtl dem Nutzer die Möglichkeit geben, selbst zu bestimmen, ab welchem Logging-Level geloggt werden soll).
Aber eigtl seh ich das genau so wie Dravere - entweder, der Fehler wird gefangen und der Nutzer der lib loggt diesen irgendwie oder er wird gefangen und verworfen oder er wird nicht gefangen - im zweiten Fall ist ihm der Fehler offensichtlich egal und im dritten Fall will er sie nicht fangen oder die Doku ist zu schlecht bzw er ist zu faul, diese zu lesen...
bb
Damit bin ich nicht ganz einverstanden. Natürlich sollte in der Release-Version kein automaitsche Logging mehr stattfinden (oder es sollte zumindest ausgeschaltet werden können). In der Debug-Version hat es aber durchaus etwas für sich, Fehler bereits beim Werfen in ein Log zu schreiben. Das kann beim Debuggen manchmal sehr hilfreich sein. Allerdings ist es wohl nicht ganz einfach, sich dafür eine passende Infrastruktur zu überlegen.
Stefan.
-
@DStefan,
unskilled hat ja gar nichts anderes gesagt ...
@eulentier,
Ich bin dagegen aus mehreren Gründen. Vielleicht schätzen das andere anders ein, aber ich tue es so:
1. Es ist nicht die Aufgabe der Exceptionklasse -> Verwirrt.
2. Es ist nicht die Aufgabe der Engine -> Verwirrt.
3. Es ist unangenehm für den Benutzer der Engine, weil er dann keine Kontrolle oder zu wenig Kontrolle darüber hat. Vielleicht möchte er ganz anders loggen.
4. Falls eine Exception vom Benutzer der Engine nicht gefangen wird, denn sobald er sie fängt, kann er ja selber loggen, dann stopt das Programm im Debugmodus und man kann debuggen. Der GDB zum Beispiel hat sogar die Möglichkeit zu stoppen, sobald eine Exception geworfen werden soll, also egal ob die mal später gefangen wird oder nicht.Ich sehe daher eher Vorteile auf den ersten Blick und auf dem zweiten eine Menge an Nachteilen. Ich habe es nicht gern, wenn mir Bibliotheken in Bereiche reinpfuschen, welche sie gar nichts angehen.
Grüssli
-
Aaaalso, ich sage euch jetzt mal wie ich es gemacht habe. Freue mich über Meinung, allerdings möchte ich gleich dazu sagen, dass ich keinen "Designkrieg" aus sowas machen will und mich nicht zu lange mit sowas wie Logging aufhalten will.
Ich habe eine Exception Hierarchie (Basisklasse MeinNamespace::Exception). In all den Exception Klassen gibt es nicht eine Zeile Logging (die Exception Klassen haben also keine Ahnung vom Logging).
Dann habe ich ein Makro fürs Werfen von Exceptions:
#define THROW_EXCEPT(exceptionType, description) LOG_EXCEPT(description); throw exceptionType(description, \ __FUNCTION__, __FILE__, __LINE__) // So sieht dann bei mir das Werfen im Code aus: THROW_EXCEPT(FileNotFoundException, "Datei Foo wurde nicht gefunden.");Mein Makro macht mittels des Makros LOG_EXCEPT() einen Log Eintrag und wirft dann die Exception. Von LOG_EXCEPT() gibt es 2 Versionen: Eine für den Debug Modus und eine für den Release Modus. Im Release Modus wird nur der Typ und die Meldung geloggt (also keine Internas) und im Debug Modus ist LOG_EXCEPT() geschwätziger und loggt noch Funktion, Quelldatei, Zeile usw.
Mein System kurz zusammengefasst:
+ Exception Klassen wissen nichts vom Logging.
+ Per Hilfsmakro werfe ich gleichzeitig eine Exception und logge ich.
+ Ich logge sowohl im Debug als auch im Release Modus bei einer Exception. Einige meinten ja, dass man das nicht machen soll, aber mir leuchtet das nicht ein. Wenn beim "Kunden" das Programm abstürzt, dann will ich so viele sinnvolle Infos wie möglich erhalten durch die log Datei. Wenn ich jetzt Engine Exceptions beim Werfen nicht mitlogge, kann ich mir nicht sicher sein ob nicht eine Nichtgefangene Exception der Grund war.
Den Unterschied Debug/Release unterscheide ich dadurch, dass mein Debug Loggen echt geschwätzig ist und mein Release Loggen nur sagt, dass eine Exception gefolgen ist.(PS: Dank der Makroverwendung könnte ich ganz fix eine Release Version von THROW_EXCEPT definieren, die NICHT LOG_EXCEPT aufruft).
Freue mich über Rückmeldungen:)
-
Noch block-klammen drum, damit nicht
if(a==5) THROW_EXP(...); esGeht();nicht mehr geht.
Es würde in deiner Version nur bei a==5 loggen, aber immer throwen.
-
volkard schrieb:
Noch block-klammen drum, damit nicht
if(a==5) THROW_EXP(...); esGeht();nicht mehr geht.
Es würde in deiner Version nur bei a==5 loggen, aber immer throwen.Ah, hab ich glatt übersehen. Danke!
