C++ frequently questioned answers
-
Warum soll man allgemein (also nicht nur in C++) für Ctor Fehlschläge nicht Exceptions verwenden? In jeder 3ten Zeile erst mal zu prüfen ob mein Object n Errorflag gesetzt hat ist doch nicht besser.
-
HouseOfTheRaisingSun schrieb:
Warum soll man allgemein (also nicht nur in C++) für Ctor Fehlschläge nicht Exceptions verwenden? In jeder 3ten Zeile erst mal zu prüfen ob mein Object n Errorflag gesetzt hat ist doch nicht besser.
Weil laut Autor Exception in C++ ein kaputter Mechanismus sind. Genauso wie Vererbung, virtuelle Methoden, Access Control, Destruktoren, Resourcen Management, Zeiger, Templates, Operatoren Ueberladung, inlining,... eigentlich so ziemlich alles.
Aber frag da lieber Jester, der erklaert dir das warum man Exceptions in C++ eigentlich nicht verwenden kann und deshalb Konstruktoren in C++ garnicht sinnvoll verwendbar sind und dadurch Objekte generell nicht (vorallem da ja Destruktoren auch nicht richtig funktionieren) und da spaete Bindung und Vererbung generell in C++ sowieso komplett kaputt ist, sollte man lieber gleich auf alles verzichten. Jester kennt sich da sicher aus. Frag ihn mal.
-
Erinnert mich ein wenig an diese Fun-Seite.
-
Shade Of Mine schrieb:
zB reitet der autor auch gerne darauf herum dass Destruktoren nicht fehlschlagen duerfen.
wieso nicht dürfen? schiefgehen kann immer was. z.b. funktionen die fehlschlagen oder sogar ein heap crash. in dem fall könnte man ja auch 'ne exception abschicken. natürlich keine, die mit 'new' erzeugt wurde, wenn der heap kaputt ist. aber wie ich die lage einschätze, ist das alles in c++ insider-kreisen strengstens verboten.
-
~fricky schrieb:
wieso nicht dürfen? schiefgehen kann immer was. z.b. funktionen die fehlschlagen oder sogar ein heap crash. in dem fall könnte man ja auch 'ne exception abschicken. natürlich keine, die mit 'new' erzeugt wurde, wenn der heap kaputt ist. aber wie ich die lage einschätze, ist das alles in c++ insider-kreisen strengstens verboten.
Welche Sprache kann da noch was vernünftiges machen? Es werden soviele logik Fehler in Programme eingebaut, dass ein Destruktor der aufgrund von total extoischen Problemen nicht funktionieren könnte doch vollkommen egal ist.
-
~fricky schrieb:
aber wie ich die lage einschätze, ist das alles in c++ insider-kreisen strengstens verboten.
Und in welcher Sprache nicht?
Nicht umsonst schreibt man in Java immerfinally { if(f!=null) { try { f.close(); } catch(Exception e) {} } }
Weil man nicht sinnvoll reagieren kann (in 99% der Faelle).
Fuer soetwas kritisches gibt es dann andere Moeglichkeiten - die natuerlich umstaendlicher sind, aber man braucht sie ja auch eigentlich nie (und wenn man sie mal braucht dann ist es natuerlich nervig wenn es umstaendlich ist, aber solange es machbar ist, ist es imho ok).
java finalizers duerfen uebrigens auch nicht fehlschlagen.
Sag mir mal eine Sprache wo es regelmaessig vorkommt dass cleanup funktionen fehlschlagen und man sinnvoll darauf reagiert. problem ist halt: wenn ich sage: trenne die Verbindung zum Server und es schlaegt fehl, was mache ich dann? Mich aergern und die Verbindung halt offen lassen uU vorher einen forced shutdown probieren (nur ist ein forced shutdown nicht immer moeglich, zB ein delete bietet mir keine moeglichkeit fuer einen forced shutdown) und danach bin ich ratlos.
Alles hat immer vor und nachteile.
-
~fricky schrieb:
Shade Of Mine schrieb:
zB reitet der autor auch gerne darauf herum dass Destruktoren nicht fehlschlagen duerfen.
wieso nicht dürfen? schiefgehen kann immer was. z.b. funktionen die fehlschlagen oder sogar ein heap crash. in dem fall könnte man ja auch 'ne exception abschicken. natürlich keine, die mit 'new' erzeugt wurde, wenn der heap kaputt ist. aber wie ich die lage einschätze, ist das alles in c++ insider-kreisen strengstens verboten.
Ich nehme Dich mal in die Insider-Kreise von C++ auf, indem ich Dir erkläre, warum ein Destruktor keine Exception werfen darf.
Das Problem ist, dass Destruktoren automatisch beim verlassen des Gültigkeitsbereiches von Stack-Variablen aufgerufen werden. Das lässt sich noch nicht mal verhindern. Der Gültigkeitsbereich kann aber auch durch eine andere Exception verlassen werden. Der Codefluß ist dann gerade zwischen einem throw und einem catch, also gerade beim auffangen einer Exception. Der Usercode wirft jetzt eine weitere Exception. Das kann nicht gut gehen. Was sollte das System denn dann machen? Die vorige Exception verwerfen und die neue auffangen? Sehr schlecht. Vielleicht die neue Exception ignorieren? Auch schlecht. Es gibt einfach keinen Ausweg. Deswegen ist das nicht erlaubt. Wobei die Sprache C++ das nicht verbietet. Wenn ich ein Objekt grundsätzlich auf dem Heap anlege und immer explizit mit delete lösche, kann ich das delete natürlich in einen try-Block packen und die Ausnahme auffangen, wenn der Destruktor fehl schlägt.
-
tntnet schrieb:
Der Codefluß ist dann gerade zwischen einem throw und einem catch, also gerade beim auffangen einer Exception. Der Usercode wirft jetzt eine weitere Exception. Das kann nicht gut gehen.
das kann gut gehen, z.b. wenn exceptions priorisiert sind (so dass handler von niederpriorisierten exceptions von höherpriorisierten exceptions unterbrochen werden können, jedoch nicht umgekehrt). nachdem der hochprio-handler fertig ist, geht's im anderen exception handler weiter. so wie mit 'nested interrupts'. wie regiert c++ denn auf eine exception in einem exception-handler? ich würde wetten, sowas ist, nach alter c++-manier, 'undefined'.
-
Was meinst du mit exception-handler?
sowas?try{ }catch(...){ throw 1; }
ganz normal.
-
~fricky schrieb:
das kann gut gehen, z.b. wenn exceptions priorisiert sind (so dass handler von niederpriorisierten exceptions von höherpriorisierten exceptions unterbrochen werden können, jedoch nicht umgekehrt). nachdem der hochprio-handler fertig ist, geht's im anderen exception handler weiter. so wie mit 'nested interrupts'. wie regiert c++ denn auf eine exception in einem exception-handler? ich würde wetten, sowas ist, nach alter c++-manier, 'undefined'.
ist technisch nicht trivial.
denn ab wann gilt eine exception als behandelt? nach dem catch()? was wenn ich im catch() resourcen kille die bei dem anderen execution tree (von der low priority exception) aktiv sein muessten -> sehr komplex das ganze mit der aktuellen exception mechanik.was aber geht ist die mechanik anzupassen und einen exception stack zu bauen.
eine low priority exception wird geworfen. beim aufraeumen wird eine high priority exception geworfen und wandert auf den exception stack:
wir hantieren nicht mit konkreten exceptions mehr sondern nur mit .top() vom exception stack - wir fangen also die high priority exception irgendwo und es geht weiter solange bis die letzte exception vom stack gepoppt wurde.waere moeglich sowas in c++ zu implementieren - aber wird wohl niemand machen. denn "dtors duerfen nicht werfen" ist einfacher und sinnvoller. denn anders sind transaktionen schwer zu implementieren.
-
Shade Of Mine schrieb:
ist technisch nicht trivial.
aber es dürfte auch nicht sonderlich schwierig sein. was macht c++ eigentlich, wenn zwei oder mehr exceptions gleichzeitig auftreten. gibt es eine definierte reihenfolge, in der sie abgearbeitet werden oder nicht?
Shade Of Mine schrieb:
denn "dtors duerfen nicht werfen" ist einfacher und sinnvoller.
naja, ich weiss nicht, ob das einfacher ist. wer diese regel beherzigt, muss höllisch aufpassen, dass er im destruktor nix aufruft, was exceptions werfen kann. wenn man sich dessen nicht sicher ist, könnte man sich vieleicht damit behelfen, indem man den ganzen code eines destruktors in einen try(...) block packt und eventuelle exceptions sofort abfängt. aber das wird wohl auch nicht gehen, schätze ich mal.
-
~fricky schrieb:
aber es dürfte auch nicht sonderlich schwierig sein. was macht c++ eigentlich, wenn zwei oder mehr exceptions gleichzeitig auftreten. gibt es eine definierte reihenfolge, in der sie abgearbeitet werden oder nicht?
std::unexpected wird aufgerufen was terminate() aufruft.
naja, ich weiss nicht, ob das einfacher ist. wer diese regel beherzigt, muss höllisch aufpassen, dass er im destruktor nix aufruft, was exceptions werfen kann. wenn man sich dessen nicht sicher ist, könnte man sich vieleicht damit behelfen, indem man den ganzen code eines destruktors in einen try(...) block packt und eventuelle exceptions sofort abfängt. aber das wird wohl auch nicht gehen, schätze ich mal.
das aufpassen dass keine exception fliegt ist trivial. da jede release funktion ja nicht werfen darf.
warum es sinn macht ist, weil du damit rollbacks machen kannst. das kannst du nur dann wenn release funktionen nicht fehlschlagen koennen.
-
Warum lasst ihr euch immer in C++-Diskussionen mit Fricky verwickeln?
-
Ich verstehs nicht schrieb:
Warum lasst ihr euch immer in C++-Diskussionen mit Fricky verwickeln?
weil er ab und an doch eine interessante frage stellt der es wert ist nachgegangen zu werden.
-
Shade Of Mine schrieb:
std::unexpected wird aufgerufen was terminate() aufruft.
ahso, und dort kann man sich sicherlich einklinken, eben nicht terminate() aufrufen, sondern stattdessen die anderen exceptions bearbeiten bzw. so ein stackbasiertes system, wie du z.b. vorgeschlagen hast, einbauen.
Shade Of Mine schrieb:
das aufpassen dass keine exception fliegt ist trivial. da jede release funktion ja nicht werfen darf.
vorausgesetzt diese funktionen sind als 'destruktor-tauglich' bekannt, wovon man ja nicht immer ausgehen kann.
-
~fricky schrieb:
naja, ich weiss nicht, ob das einfacher ist. wer diese regel beherzigt, muss höllisch aufpassen, dass er im destruktor nix aufruft, was exceptions werfen kann. wenn man sich dessen nicht sicher ist, könnte man sich vieleicht damit behelfen, indem man den ganzen code eines destruktors in einen try(...) block packt und eventuelle exceptions sofort abfängt. aber das wird wohl auch nicht gehen, schätze ich mal.
Dein "schätze ich mal" sagt mir, dass Du Dir unsicher bist und nicht wirklich weisst, wie C++ funktioniert.
Du musst höllisch aufpassen, keine Endlosschleifen zu programmieren, nicht auf null-Zeiger zuzugreifen oder auf der Straße von einem Auto angefahren zu werden. So ist das Leben nun mal.
Lern mal richtig C++. Dann kannst Du anfangen, Dir Gedanken zu machen, wie man es besser machen könnte. Solange Du noch nicht weisst, wie das funktioniert, solltest Du mal lieber nicht so unqualifiziert rumkritisieren (gilt übrigens auch für die genannte Website).
-
tntnet schrieb:
Du musst höllisch aufpassen, keine Endlosschleifen zu programmieren, nicht auf null-Zeiger zuzugreifen oder auf der Straße von einem Auto angefahren zu werden. So ist das Leben nun mal.
schon klar, kompromisse muss man überall eingehen. es ist ja auch OK, solange die vorteile die nachteile überwiegen. bei C++ (exceptions, destruktoren, etc.) scheint dieses verhältnis allerdings nicht ganz zu stimmen.
tntnet schrieb:
Lern mal richtig C++. Dann kannst Du anfangen, Dir Gedanken zu machen, wie man es besser machen könnte.
danke für den gut gemeinten tip. aber nach allem, was ich bisher über C++ mitbekommen habe, verspüre ich wirklich nicht den drang danach, es weiter zu vertiefen.
-
~fricky schrieb:
schon klar, kompromisse muss man überall eingehen. es ist ja auch OK, solange die vorteile die nachteile überwiegen. bei C++ (exceptions, destruktoren, etc.) scheint dieses verhältnis allerdings nicht ganz zu stimmen.
Und warum?
Release funktionen dürfen in kaum einer sprache fehler produzieren...
siehe zB free()
-
Shade Of Mine schrieb:
Release funktionen dürfen in keiner sprache fehler produzieren...
das ist doch keine frage der sprache. eine release-funktion, die nur eine statusvariable setzt, wird mit einer wahrscheinlichkeit von 0.999... immer klappen. aber bei einer, die z.b. was über eine netzwerkverbinung schicken muss, dann diese verbindung schliessen muss, etc. sieht's schon schlechter aus. hierbei stellt sich die frage, welchen reellen gebrauchswert destruktoren in solchen fällen haben. eine programmiersprache sollte dem benutzer eigentlich nicht aufzwingen, wie er release-funktionen zu bauen hat.
-
ready_sep15-r115-1_7.txt;20;30