Konstruktor auch ohne Erfolg realisierbar?
-
CStoll schrieb:
Und wie soll ein Konstruktor etwas als Rückgabewert übergeben? Das einzige, was der zurückgeben kann, ist ein fertig konstruiertes Objekt, also bleibt als Alternative zu einer Exception nur, this in einen Zombie-Status zu versetzen. Und wenn jede Methode erst überprüfen muß, ob sie auf ein intaktes Objekt angewendet wurde, bremst du damit dein gesamtes Programm unnötig aus.
Du würdest fstream anders realisieren?
-
delete this;
-
class MyClass { public: MyClass(int &riRes) { if (....) { riRes = -1; return; } } };Ist also nur ein Quasirückgabewert. Deswegen hab ich's auch weiter oben mit "" geschrieben.
-
@Bashar: Nicht unbedingt - bei den IO-Streams kann es ja auch vorkommen, daß ein bereits existierendes Objekt später ungültig wird, also ist der inaktiv-Status sowieso notwendig. Aber bei Objekten, die nach einer erfolgreichen Initialisierung (aka Erschaffung) gültig bleiben, kostet es nur Zeit und Platz mitzuschreiben, ob sie nutzbar sind.
@Maffe: Also da ist die Exception-Variante auf jeden Fall eleganter und sicherer:
int dummy;//damit der Ctor glücklich ist MyClass test(dummy); test.do_something();Wenn du vergisst, das Ergebnis zu kontrollieren (und kein Compiler der Welt wird dich darauf aufmerksam machen, daß dort etwas wichtiges zurückgekommen ist), arbeitest du mit einem kaputten Objekt.
Im Gegensatz dazu:
try { MyClass test; test.do_something(); } catch(...) {...}Wenn der Ctor eine Exception geworfen hat, springt das Programm ohne Umwege zum catch-Block - also werden auch alle Anweisungen umgangen, die mit dem (jetzt unbrauchbaren) Objekt arbeiten wollten.
-
Maffe001 schrieb:
LOL Nein ich überprüfe nicht den Return von "printf".
Ich überprüf ihn immer bei Sachen, die ich selbst geschrieben habe. Den traue ich natürlich nicht so ganz. ...Mit "trauen" (im Sinne von "falsch programmiert") hat das eigentlich nicht viel zu tun, sondern damit, dass sich zur Laufzeit (z.B. durch Usereingaben, DB-Inhalte, NetzwerkMSG, ...) Situationen ergeben können, die falsche Ergebnisse liefern. Und da spielt es eigentlich keine Rolle, ob das bei einer selbstgeschriebenen Funktion oder einem printf() passiert. was hilft Dir z.B. das Einlesen mit scanf(), wenn die vorherige Anzeige (printf()) schief gelaufen ist ?
Oder erst recht problematisch ist ein gescheitertes sprintf() ...Gruß,
Simon2.
-
Doch mit "trauen" hat das manchmal auch zu tun. Bei einigen Multithreading- oder Timergeschichten unter Windows, sind schon manchmal Effekte aufgetreten, an die ich nicht im Traum gedacht habe. (Ja ich weiss, der Fehler lag sicher an meinem Konzept.) Aber gut, jetzt wird's philosophisch.
Ansonsten geb ich dir natürlich Recht. Man muss halt versuchen alle möglichen Zustände abzudecken.
Was mich bei Exceptions halt immer gestört hat, sind diese try...catch-Blöcke, die den Code doch recht verschandeln. Aber ich bin bekehrt. Habt ihr gut gemacht.

Ich denke mal, dass die meisten von euch nicht an jeder Stelle, wo ein Objekt erzeugt wird, solche Blöcke einbauen, sondern eher eine zentrale Stelle haben, an denen diese Kontrolle gemacht werden. Oder seh ich das falsch?
-
Maffe001 schrieb:
...Doch mit "trauen" hat das manchmal auch zu tun....
Dagegen habe ich auch nichts ... eben manchmal !
Ich wollte nur aussagen: Selbst da, wo man einem Programm traut, ist Fehlerbehandlung sinnvoll.
Allerdings: Wenn Du einem Code nicht "traust", hilft auch Fehlerhandling nicht wirklich weiter, weil: Wer sagt Dir denn, dass der schlechte Programmierer überhaupt eine Fehlersituation erkennt und (sei es via Returncode oder exception) sauber handlet ?
Ich behaupte mal, dass die meisten Programmierfehler nicht durch Fehlerhandling des Aufrufers unschädlich gemacht werden können ... da gibt dan die aufgerufene Funktion stumpf eine 7 statt einer 5 zurück und dem Anwender werden Stromstöße durch die Hoden gejagt und kein catch(...) der Welt hilft ihm.
Maffe001 schrieb:
...
Ich denke mal, dass die meisten von euch nicht an jeder Stelle, wo ein Objekt erzeugt wird, solche Blöcke einbauen, sondern eher eine zentrale Stelle haben, an denen diese Kontrolle gemacht werden. Oder seh ich das falsch?JETZT kommt der Punkt, wo die Sache interessant wird: Beim Fehlerhandlingkonzept !

Da kann ich Dir nur sagen, wie ich das entscheiden: Immer dort, wo ein Programm in einer Ausnahmesituation "noch etwas machen" (= selbsttätig regieren) kann, gehört Fehlerhandling (try/catch) hin ... und sonst nirgendwo !
Eine exception abzufangen, bloß um sie weiterzuwerfen (ggf. umgewandelt), ist IMO Unsinn. Man braucht auch GAR keinen try/catch, wenn man möchte/es nicht stört, dass das Programm einfach terminiert bei einer exception.
Ausnahmen:
- Manche Komponentenschnittstellen sind so definiernt, dass keine exceptions sie queren dürfen oder (aus technischen Gründen) können. Hier muss man ein catch(...) einfügen und auf die schnittstellenkonforme Fehlerhandlingtechnik mappen.
- Destruktoren sollten niemals exceptions werfen ! Also entweder nur Funktionen aufrufen, die keine schmeißen können (z.B. andere Destruktoren, delete oder ...) oder mittels catch(...) sicherstellen.Das ist ja das Schöne an den exceptions: Man braucht sie nur da zu handeln, wo man auch was tun möchte und trotzdem ist garantiert, dass das Programm nicht falsch arbeitet.
Gruß,
Simon2.
-
Maffe001 schrieb:
Doch mit "trauen" hat das manchmal auch zu tun.
OK, dann vertraust du vielleicht den Funktionen, mit denen du umgehst. Aber vertraust du dem Nutzer, der dein Programm bedienen will, genauso bedingungslos?
PS: Und der Vorteil der Exception-Behandlung ist, daß du den Fehler dort behandeln kannst, wo du weißt, wie du reagieren mußt. Wenn du die Rückgabewerte von (z.B.) scanf() nicht sofort auswertest oder speicherst, verschwindet der mögliche Fehler ins Nirvana und du kannst im Nachhinein nicht mehr feststellen, daß etwas passiert ist - und diese Vermischung von Fehlerauswertung und normalem Code ist viel schlimmer als ein geeignet gesetztes try/catch. Mal ein Beispiel:
//"klassische" Fehlerbehandlung while(!ende) { int scanres; ... int value; scanres = scanf("%d",&value); if(scanres!=1) { fprintf(stderr,"Eingabefehler\n"); break; } ... //und solche Blöcke können - in verschiedenen Variationen - noch einige Male in der Schleife vorkommen } //Fehlerbehandlung mit Exceptions cin.exceptions(ios::failbit|ios::badbit);//Schalte Exceptions für cin an try { while(!ende) { ... int value;cin>>value; } } catch(std::exception& e) { cerr<<"Eingabefehler "<<e.what()<<endl; }Was sieht jetzt besser aus?
-
CStoll schrieb:
OK, dann vertraust du vielleicht den Funktionen, mit denen du umgehst. Aber vertraust du dem Nutzer, der dein Programm bedienen will, genauso bedingungslos?
Da ist vielleicht der Haken. Programme, die mit einem Nutzer interagieren, hab ich bis jetzt nur wenig geschrieben. Bis jetzt waren es eher Programme, die mit externen Geräten kommunizieren und deren Antworten dann in eine Datenbank geschoben oder vielleicht auch einfach an eine Datei, Konsole etc. weitergeleitet werden. Da diese Geräte hohen Standards gerecht werden müssen, mit reduntanten Systemen ausgestattet sind usw. klappt das bis jetzt ganz gut.
Natürlich ist die Variante mit den Exceptions eleganter. Ich sagte ja schon, dass ihr mich bekehrt habt.

Ich gelobe, mich nicht mehr gegen Exceptions zu wehren. :pJetzt muss ich mir nur noch ein ordentliches Konzept angewöhnen, damit mein Code nicht all zu arg von try...catch-Blöcken "verunstaltet" wird.
-
Maffe001 schrieb:
...Programme, die mit einem Nutzer interagieren, hab ich bis jetzt nur wenig geschrieben. Bis jetzt waren es eher Programme, die mit externen Geräten kommunizieren und deren Antworten dann in eine Datenbank geschoben oder vielleicht auch einfach an eine Datei, Konsole etc. weitergeleitet werden. Da diese Geräte hohen Standards gerecht werden müssen, mit reduntanten Systemen ausgestattet sind usw. klappt das bis jetzt ganz gut....
Oha - also ich schreibe auch im Wesentlichen "unbediente Systeme" und muss sagen: Was da übers Netz, aus der DB oder der Datei kommt, ist nix besser als das, was menschliche Nutzer eintippen.

Letztlichg stammen auch dieses Daten alle von menschlicher Hand (und sei es nur die Hand, die eine BS-SW für ein Terminal geschrieben hat).
Den traue ich kein Stückchen mehr (Aunahme: RIs und "mandantory fields" beim DB2 - die prüfe ich nicht mehr nach) !
Gruß,
Simon2.
-
Hmm, na ich rede von medizinischen Geräten mit doppelten und dreifachen Absicherungen. Aber gut lassen wir das. Wir sind sowieso am Thema, des Threads vorbeigeschossen.

-
Wenn ich diesen Thread lese kommt mir Das Grauen (tm).