Wie Programm verlassen, wenn kein Parameter zurückgegeben werden darf?
-
@Shade Of Mine:
Ja, ich weiss nicht was ich noch alles schreiben soll. Ist eigentlich so einfach und ich habs jetzt mehrfach erklärt. Du schreibst selbst "Wilder zeiger irgendwo." - was willst du mehr? Wieso gehst du davon aus dass mit diesem wilden Zeiger nicht einfach *irgendwas* überschrieben wurde, zum Beispiel lebenswichtige Daten für die Module die du noch für "gut" hältst. Oder "das Dokument". Eine 0 an die erste Stelle und du speicherst ein leeres Dokument. Toll. Grosses Kino. Viel Spass mit deinen Exceptions.
-
was du von den redundanten daten gesagt hast: du brauchst fuer sowas transaktionen wenn du die komplexen daten auf dem server stabil halten willst.
ein gaengiges transaktionsmodell fuer c++ basiert auf RAII -> und das verlangt dass der dtor aufgerufen wird dh, du hast inkonsistente daten nach dem terminate. moeglich diese zu reparieren, aber wenn ne exception fliegt ist das reparieren nicht mehr noetig - weil es n automatisches rollback der transaktion gibt.Wo brauche ich für das Rollback bzw. das Transaction-Handling RAII oder einen noch lebenden Prozess? Nach dem terminate() hab ich nichtmal inkonsistente Daten wenn ich eine in-process Datenbank ala sqlite verwende, weil mir die DB brav ein Rollback macht wenn die connection unterbrochen wurde vor dem commit. Im Fall einer in-process DB ist das Teil des Recovery-Prozesses der wiederum teil des Initialisierungsvorganges ist. Wozu brauche ich also da nen Dtor oder ne Exception?
Mit einer "echten" DB schon garnicht, weil mir die auch automatisch ein Rollback macht wenn die Connection unterbrochen wird - also z.B. durch "connection reset by peer" (Socket-Fehler halt).
-
was habt ihr nur gegen exceptions

mal'n einfaches beispiel... try { schritt1(); schritt2(); schritt3(); ... // noch'n haufen anderer komplizierter kram... ... } catch (...) { // hier weiss man dass die ganze aktion in die // hose gegangen ist und kann entsprechend reagieren. // wiederholen, daten retten, programm abbrechen, // was auch immer... } ...ohne exceptions bräuchte man viele if's, flags, gotos oder sonstwas um nach einem missglückten schritt abzubrechen...
-
Shade Of Mine schrieb:
leider nicht moeglich da vernuenftige infos rein zu schreiben, weil du im terminate handler kein stack unwinding hinter dir hast - du hast also 0 ahnung vom kontext wo der fehler aufgetreten ist.
waehrend ich mit meiner exception ne bessere funktionalitaet habe: weil eben mehr infos zur verfuegung stehen um ein logfile zu schreiben. weiters werden destruktoren verlaesslich aufgerufen und ich kann entscheiden ob der fehler fatal genug war um einen sofortigen shutdown zu rechtfertigen.
sachen die ich mit terminate nicht kann.
Im Gegenteil. Bei einer Exception hast du im Normalfall so gut wie null Kontext, es sei denn du kümmerst dich explizit darum (wer macht das?). Ein terminate ruft abort auf, das generiert dir, so die ulimits das zulassen unter Unix kostenlos einen Coredump, den du dann mit dem Debugger bis ins letzte Bit untersuchen kannst. Unter Windows würde ich vermuten dass man einstellen kann, dass direkt der Debugger an der fraglichen Stelle aufpoppt.
Ums mal auf den Punkt zu bringen: Es ist genau die Tatsache, dass terminate KEIN unwinding macht, dafür verantwortlich, dass der volle Kontext erhalten bleibt. Unwinding zerstört den Kontext, bürdet dir also als Programmierer auf, den Kontext manuell mit der Exception mitzuschicken.
Übrigens wird das korrekte Aufrufen irgendwelcher Destruktoren im Absturzfall IMHO für wichtiger gehalten als es ist. Die meisten Destruktoren machen eh nur was, das sowieso vom OS erledigt wird. Bei allem anderen ist es wichtiger, dass das Programm beim nächsten Start nicht über die Überreste des letzten Absturzes stolpert, die übrigens auch von einem Stromausfall stammen können.
-
sollen keine exceptions verwendet werden, bleibt für das problem nur noch das "unsanfte" beenden des ganzen programms. mit leeren dummys zu arbeiten ist meiner meinung nach nie sauber.
da die vorliegende funktion eh eine referenz zurückgibt, wäre es angemessener, die funktion zu verändern, auch wenn dies eigentlich nicht gewünscht ist.
template<class KeyType, class ValueType> bool DictionaryAsHashTable<KeyType, ValueType>::get(ValueType& ref) { if(currentNode != NULL) { ref = currentNode->value; // falls value schon ne referenz is return 1; } else return 0; }muss sich halt der aufrufende selbst um fehlerbereinigung handeln und der methodenentwickler is fein raus

-
Ums nochmal ganz klar zu machen (@net und andere): ich bin ein grosser Fan von Exceptions. Zur Behandlung von "Laufzeitfehlern". Ich bin aber auch der Meinung dass der korrekte Weg auf die Verletzung von preconditions oder invariants zu reagieren ist das Programm ohne stack unwinding zu beenden.
-
Plotzenhotz schrieb:
...
Vonwegen verlorene Daten im Fall "Server"... blubb? ...Falls das auf meinen Einwand hin gemeint war:
Ich habe schon Server für Clienten (über ganz Deutschland verteilte Hardwareterminals unterschiedlichster Hersteller mit sehr kleinen Toleranzen - keine Chance, auf deren Implementation selbst Einfluß zu nehmen) programmiert, bei denen man mir Körperteile entfernt hätte, wenn ich nicht alles versucht hätte, um den Server am Laufen zu halten.
Ja, es gibt auch Situationen, wo ein technischer Defekt vorliegt und man wirklich nicht mehr sinnvoll arbeiten kann (deswegen Herunterfahren des Prozesses und automatischer Restart) - aber auch dann war aus Verfügbarkeitsgründen der Versuch des Aufräumens (konkret: Aktives Abmelden vom Nameservice) immer noch vorzuziehen (die Reaktionszeiten des Nameservices auf ein "unabgemeldetes Abschmieren" waren sehr hoch).Und in allen anderen Fällen (99%) haben wir auf verschiedensten Ebenen Retries eingebaut (tw. auch Retrymechnismen der Clients genutzt).
Das Teil läuft nun seit 4,5 Jahren und unsere Kunden loben einstimmig die inhaltliche wie technische Zuverlässigkeit ....
und alles ohne terminate(). :pWie gesagt: So sehr ich Dir in der Theorie auch zustimmen mag ... in der Praxis kann kaum jemand entscheiden, ob der unpassende Parameter in seiner Funktion ein terminate() rechtfertigt - weswegen der Ansatz in der Praxis eher eine untergeordnete Rolle spielen dürfte. Vielleicht programmiere ich aber auch zu wenig für menschliche Nutzer, um den Ansatz würdigen zu können.
Plotzenhotz schrieb:
...Wenn der DB-Server nicht sicher genug ist (z.B. nicht geclustert) liegt das ausserhalb der Verantwortlichkeit meines Programms ...
Nicht, wenn Du den DB-Server programmierst.

Ich habe allerdings den Eindruck, dass Dein "Im Fehlerfall tot umfallen"-Konzept sich immer mehr dem annähert, was viele hier mit exceptions umsetzen:
- Programmabbruch nur in Spezialfällen
- Ressourcen aufräumen (allerdings vom OS und nicht im Dtor)
- Kontrolle nochmal wiederbekommen (statt im catch halt im eigenen terminate-Handler zum Fehlerinfos wegschreiben, ....).
Das Einzige, was Deinen Vorschlag noch von "unserem" unterscheidet, ist eigenlich nur, dass kein Stackunwinding mehr vor Programmende stattfindet.
..- und ich weiß nicht, ob das den heiligen Krieg rechtfertigt, der hier ausgebrochen ist.Gruß,
Simon2.
-
Falls das auf meinen Einwand hin gemeint war:
Nö, das war nicht an dich gerichtet.
Wie gesagt: So sehr ich Dir in der Theorie auch zustimmen mag ... in der Praxis kann kaum jemand entscheiden, ob der unpassende Parameter in seiner Funktion ein terminate() rechtfertigt - weswegen der Ansatz in der Praxis eher eine untergeordnete Rolle spielen dürfte.
Jau
Ich bin halt der Meinung ich sollte mir erstmal über die Theorie im Klaren sein, die Gefahren kennen, wissen was passieren kann, warum soetwas "grundlegendes" wie stack unwinding Schaden anrichten kann. Dann kann ich diverse Faktoren gegeneinander abwägen, und entscheiden was wichtiger ist, bzw. was sinnvoller ist. Und ich denke dass es Fälle gibt wo man alles ausschliessen muss was theoretisch irgendwie gefährlich sein könnte und das Programm lieber sofort beendet und neu startet, genauso wie es Fälle gibt wo man sinnvollerweise komplett auf Error-Checking/-Handling verzichtet. Das meiste wird sich natürlich irgendwo im Bereich dazwischen ansiedeln.Das Einzige, was Deinen Vorschlag noch von "unserem" unterscheidet, ist eigenlich nur, dass kein Stackunwinding mehr vor Programmende stattfindet.
Genau. Weil Stack-Unwinding gefährlich ist
*duck-und-renn*BTW (in Bezug auf ein früheres Posting von dir): dass eben kein stack unwinding passiert wenn eine Exception nirgends gefangen wird ist auch der Grund warum einige Leute immer wieder predigen: "catch(...) + rethrow" (als "finally" Ersatz) ist böse, Guards (die dann im Dtor cleanup durchführen) sind gut. Weil durch "catch(...) + rethrow" eben stack unwinding bis zu einem gewissen Punkt erzwungen wird, auch wenn die weitergeworfene Exception dann im Endeffekt keiner fängt. Was aber wieder ein anderes Thema ist.
Und jetzt geh ich pennen, gute Nacht

-
Plotzenhotz schrieb:
Vorweg ein paar Kleinigkeiten. Diverse Files (File-Handles meine ich), Speicher, sonstige Resourcen (Sockets, ...) werden normalerweise wenn ein Prozess terminiert vom OS aufgeräumt, darum braucht man sich keine Sorgen zu machen.
Du machst dir das viel zu einfach. Wir reden hier nicht von Windows oder Linux, die sowas evtl. machen. Hier geht es um ISO C++, und das gibt keinerlei Garantie dafür. Deshalb ist es grundsätzlich eine feine Sache, Destruktoren abarbeiten zu lassen. Allein das reicht schon aus, um Exceptions expliziten Aufrufen von Funktionen wie terminate, abort, exit oder was auch idR den Vorzug zu geben.
Plotzenhotz schrieb:
Weiters sollte man wissen dass das Stack-Unwinding nur dann passiert wenn die Exception auch irgendwo gefangen wird.
Ja, das kann aber keine Begründung sein. Wer eine Exception wirft, macht irgendwas falsch, wenn er nicht vorhat, sie zu fangen.
Plotzenhotz schrieb:
Wird sie nicht gefangen wird der Prozess einfach so terminiert - macht dann auch keinen Unterschied mehr.
Nö, einfach so nicht. Es wird terminate() aufgerufen.
Plotzenhotz schrieb:
Nu zu dem Grund warum ich meine dass es in Fällen wo man eine Precondition verletzt sieht schlauer ist das Programm einfach abzubrechen, und zwar ohne Stack-Unwinding. Einfache Antwort: eben genau weil dann kein Stack-Unwinding mehr passiert, also keine Destruktoren mehr laufen.
Destruktoren auszuführen hat nur dann einen Sinn wenn man davon ausgeht dass das Programm noch in einem gültigen Zustand ist.Aber genau deshalb wirft man doch Exceptions, weil das Programm sich zu diesem Zeitpunkt durch einen Fehler von einem definierten in einen undefinierten Zustand verändern kann. Ist das Programm vorher schon in einem undefinierten Zustand, dann ist das ein logischer Fehler des Programmierers und nicht der Verwendung von Exceptions zuzuschreiben.
Kleines Beispiel: jemand schreibt eine Container Klasse mit einer Funktion, um mehr Speicher anzufordern.void resize(size_t n) { delete[] p_; p_ = new T[n]; }Du kommst jetzt daher und sagst, Exceptions sind falsch, da Preconditions nicht mehr erfüllt sind, und durch Stack-Unwinding Unsinn passiert. Du hast in dem Beispiel natürlich recht. Das ist aber keine Lösung. Ist es denn nicht tausend mal besser, einfach die Logik zu korrigieren?
void resize(size_t n) { T* tmp = new T[n]; delete[] p_; p_ = tmp; }Schon sind wieder alle Preconditions erfüllt und Exceptions steht nichts mehr im Wege. Ob das immer so möglich ist, ist natürlich eine andere Frage. Aber so sollte man doch grundsätzlich erstmal an die Problematik herangehen, anstatt zu schreien, Stack-Unwinding ist böse und nimm besser terminate.
Plotzenhotz schrieb:
Wo dieser Fehler genau liegt können wir nicht wissen, der kann direkt in der aufrufenden Funktion liegen, oder in einem ganz anderen Modul.
Ich formuliere das mal etwas anders. Wenn zum Zeitpunkt eines throw's Preconditions nicht erfüllt sind, und sich das Programm bereits in einem undefinierten Zustand befindet, liegt der Fehler 60cm vorm Monitor.

Plotzenhotz schrieb:
Der Denkfehler liegt also IMHO darin anzunehmen es sei sicher noch irgendwelchen Code auzuführen wenn ein unbekannter Fehler dazu geführt hat dass ein Ereignis eingetreten ist welches per definitionem nie eintreten darf.
Was sind für dich denn "unbekannte" Fehler? Wenn ich eine Exception fliegen lasse, und mich auf das Stack-Unwinding verlasse, dann sind das immer bekannte Fehler. Bei Hardware- oder OS-Exceptions wird sowieso kompromisslos weggeschossen ohne Stack-Unwinding. Dafür brauche ich kein terminate().
Plotzenhotz schrieb:
Ich meine man sollte zwischen 'Exceptions' und 'Errors' unterscheiden. Eine Exception ist eben etwas was vorkommen kann und darf wenn das Programm 100% Fehlerfrei ist. Für so einen Fall würde ich NICHT vorschlagen terminate() aufzurufen - wäre ja komplett doof. Für den Fall allerdings dass etwas eintritt was nur passieren kann wenn das Programm eben NICHT 100% OK ist, man also einen Programmierfehler "gefunden" hat, in dem Fall wäre es oft schlauer das Programm abzuschiessen.
Viele Programmierer meinen solche Fälle sollte man in Release garnicht prüfen, dafür müsse ein assert() reichen.
All die Diskussion, und du willst uns nur sagen, dass du lieber terminate anstatt assert verwendest? Oder wie ist das zu verstehen? Wobei ich das bedenklich finden würde, wenn es so wäre. Unterscheidest du nicht zwischen Programmier- (Logik-) Fehlern und Runtime Fehlern?
-
So Leute ich hab mich nu registriert. Nicht als "Plotzenhotz" - das mag wohl einige verwirren, aber egal.
Lies doch bitte einfach was ich schon 3x hier geschrieben habe. Du hast ganz eindeutig nicht verstanden wovon ich rede. Danke und gute Nacht.
-
Tja, wenn du meinst.
Mit der Einstellung wirst du aber schlechte Chancen haben, mal was neues kennenzulernen oder dich gar weiterzuentwickeln.