Konstruktor auch ohne Erfolg realisierbar?
-
Hallo,
ein simple c++ Frage. Kann ich einen Konstruktor auch so implementieren, dass bei einem Fehler innerhalb des Konstruktors( z.b. Fehler bei irgendwelchen Schnittstellen-Konfigurationen) dieser abgebrochen wird, und dann z.b. NULL zurück gegeben wird? Muss ich hier etwas spezielles beachten (z.B. bleibt dann trotzdem ein Objekt im Speicher zurück wenn ich den Konstruktor "abbreche"?)?
Danke
Gustav
-
Wenn der Konstruktor regulaär beendet ist, hast du ein komplettes Objekt vorliegen. Um Fehler zu behandeln, bleiben dir nur zwei brauchbare Möglichkeiten:
- du definierst ein Flag im Objekt, ob es intakt ist (dann müssen alle anderen Methoden bei Aufruf dieses Flag abfragen, bevor sie irgendwas machen)
- du beendest den Ctor nicht regulär (z.B. per exit() (mitunter etwas zu radikal) oder mit einer Exception)
-
es wird so ode so ein objekt erzeugt... du musst in deiner klasse ein flag setzen welcher du dann beim verwenden der klassen methoden etc. abfrägst und checkst ob das objekt gütlig ist...
-
bei solch "kritischen konstruktionen" von objekten würd ich ne factory basteln, die instanzen des objekts liefert, oder wenn es nicht konstruiert werden konnte, halt nen null pointer.
fehler bei der konstruktion direkt im ctor zu behandeln find ich nicht so schön.
-
Oder du behilfst dir einfach, in dem du in der Schnittstelle nen Rückgabewert einbaust, den dann auswertest und dann entscheidest, ob du das Objekt weiter verwendest oder nicht.
-
Also scheint wohl doch nicht so einfach zu sein wie ich dachte. Dann wird wohl meine bisherige Realisierung einfacher sein. Bisher läuft das so:
Konstruktor -> lediglich private Variablen initialisieren
init() Methode -> reservieren von Speicher + Schnittstellen initialisieren/konfigurieren.
restliche Methoden -> prüfen ob Schnittstelle initialisiert ist. Erst dann weiter...Gruß
Gustav
-
Ja, das ist eine Methode (siehe mein Beitrag oben). Die Alternative wäre es, den Ctor im Fehlerfall über throw zu verlassen, dabei wird das Objekt auch wieder demontiert, das du gerade nicht anlegen konntest:
class test { public: test(int value) { if(value<0) throw std::out_of_range("bitte keine negativen Werte angeben"); ... } }; ... try { test t1(4711); test t2(-1); ... } catch(std::exception& e) { cerr<<"Fehler: "<<e.what(); }Der Vorteil liegt auf der Hand - du kannst im weiteren Verlauf sicher sein, daß dein Objekt ordentlich initialisiert wurde. Auf der anderen Seite muß dein Programm die möglichen Exceptions auch abfangen und geeignet darauf reagieren.
-
Hmm, also da finde ich meine Variante besser.
Wenn ich dich jetzt richtig verstanden habe, behälst du dein Objekt und beim Methodenaufruf bekommst du dann die Nachricht, ob die Aktion ausführbar ist oder nicht.[Edit] CStoll war schneller. Tu einfach so, als ob der Beitrag hier vor seinem stehen würde.
[/Edit]
-
Maffe001 schrieb:
Hmm, also da finde ich meine Variante besser. ...[/Edit]
Hmmm also ich finde CStolls Variante besser, weil man
- nicht an x verschiendenen Stellen Gültigkeitsprüfungen einbauen muss (in der Klasse UND in jedem Nutzer),
- man mit einem "ungültigen Objekt" sowieso nichts anfangen kann ... weshalb es sinnlos ist, eines zu erzeugen (wenn A eines erzeugt und B weitergibt ... was soll B dann machen, wenn es beim Aufruf einer Methode einen "ungültiges Objekt"-Error geliefert bekommt ?) und
- die Aufrufer exceptions nur schwer "vergessen" können ... eine Returncodeabfrage dagegen ist schnell mal vergessen.
Gruß,
Simon2.
-
Danke für die Beiträge. Ich werd mal etwas konkreter:
1. Hauptprogramm möchte ein Objekt der Klasse Test erzeugen.
2. Test versucht eine Schnittstelle zu konfigurieren. Dabei Misserfolg soll Test es noch x-mal versuchen. Danach muss Test den Misserfolg weitergeben (z.B. Rückgabewert).
3. Wenn Hauptprogramm den Misserfolg mitbekommt, soll das Objekt der Klasse Test gelöscht werden und mit einer Fehlerroutine fortgefahren werden.Bei meiner Methode:
1. Objekt erzeugen
2. Objekt-initroutine bei bedarf bis zu x mal aufrufen
3. wenn nicht erfolgreich -> deleteDie Idee mit der factory hat sich gut angehört. Wie würde diese aussehen?
so in etwa?:
1. Objekt erzeugen (über factoryklasse?!)
2. Factory behandelt das ganze wie oben(also objekt erzeugen + x-mal init()), bei Erfolg gibt sie Objekt zurück, bei Misserfolg NULL.
2. prüfe auf Objekt = NULL
-
[Edit]
@Simon2:
[/Edit]
Deswegen hab ich ja auch geschrieben, er solle so tun, als ob mein Beitrag über dem von CStoll steht. Ich wollte die Exceptionvariante nicht kritisieren oder meine als die bessere hinstellen.
Ich persönlich mag Exceptions nicht. Ich hab's mir so angewöhnt. Und vergesse eigentlich auch keine Überprüfung.
Ich denke mal, dass es halt wirklich nur eine Sache der Gewöhnung ist.
-
Ja also Exceptions würde ich auch gerne vermeiden. Bin auch kein Freund davon. Wenns ohne geht hät ich nix gegen

-
Maffe001 schrieb:
Ich persönlich mag Exceptions nicht. Ich hab's mir so angewöhnt. Und vergesse eigentlich auch keine Überprüfung.
"Eigentlich nie" heißt "einmal in zwei Stunden", ja ja. Aber Dummheit, Trägheit und Sturheit sind eben nicht totzukriegen.

-
Gustav Hummel schrieb:
Die Idee mit der factory hat sich gut angehört. Wie würde diese aussehen?
so in etwa?:
1. Objekt erzeugen (über factoryklasse?!)
2. Factory behandelt das ganze wie oben(also objekt erzeugen + x-mal init()), bei Erfolg gibt sie Objekt zurück, bei Misserfolg NULL.
2. prüfe auf Objekt = NULLso ungefähr. das grundprinzip ist, dass die factory alle nötigen daten besorgt und sobald sie vorliegen, ein objekt erzeugt. d.h. deine klasse braucht keinen init ballast und auch kein exception handling etc. das macht alles die factory, und wenn das erzeugen erfolgreich möglich war, liefert sie nen schlankes, vollständiges objekt zurück. wenn also die daten nicht besorgt werden konnten, wurde auch zu keinem zeitpunkt versucht, ein objekt anzulegen.
-
@Kenner....:
Was soll ich da jetzt zu sagen?
Wie gut, dass jeder seine Meinung haben darf.Nur mal so: Ich kann kein "nie" bei mir entdecken.
Getreu nach dem Motto: "Nobody is perfect.", vergess ich die Überprüfung auch mal. Aber es ist die Ausnahme. 
-
Maffe001 schrieb:
Nur mal so: Ich kann kein "nie" bei mir entdecken.
Getreu nach dem Motto: "Nobody is perfect.", vergess ich die Überprüfung auch mal. Aber es ist die Ausnahme. 
Aber einen guten Grund, Exceptions nicht zu benutzen brauchst du offensichtlich auch nicht. Da müsstest du nicht ständig sinnlose Überprüfungen von sinnlosen Objekten durchführen...

-
@Kenner...:
Also wenn du rumtrollen willst, warum tust du's nicht woanders?
Du magst wahrscheinlich keinen Rosenkohl und trotzdem werd ich nicht versuchen ihn dir aufzuzwingen. Deine Begründung, warum du ihn nicht magst, wird eher dürftig ausfallen. Gut aber das ist dein Ding.@alle anderen:
Sorry, dass ich da nochmal drauf eingestiegen bin. Intolleranz find ich einfach nur....
Damit sind dann auch meine Reaktionen auf "Kenner" beendet.
-
Ich finde die Variante besser, wo im Konstruktor kein Fehler erzeugt werden kann

-
Auch wenn ich dir nicht das Programmieren ohne Exceptions ausreden will, möchte ich hier nur mal die Gründe die für eine Exception sprechen hinstellen:
a) Wenn man Standardkonform programmiert, wird man zwangsweise Exceptions behandeln müssen (die STL wirft Exceptions, ebenso wie new).
b) Exceptions sind Ausnahmefälle, keine Regeln, der Rückgabeparameter einer Funktion sollte so gewählt werden das er die Regelfälle sinnvoll abdeckt.
c) Rückgabewerte darf man nicht vergessen, Exceptions kann man nicht vergessen (Sonst knallt es, wo beim Rückgabewert das Programm einfach irgendwas - ggf. sehr verkehrtes/schlimmes - tut).
d) Exceptions muss man nicht zwingend am Ort des Auftretens behandeln, Rückgabewerte schon.
e) Mit Exceptionhandling und Smartpointern kann man inkonsistente Daten nach einen Konstruktoraufruf leichter behandeln [bin kein Fan von der Ungarischen Notation, aber für die kurzform hier besser: m_ap=> Autopointer/Smartpointer als Member]:Fall 1 mit Smartpointer&Exceptionhandling
Klasse::Klasse() : m_apObjekt1(new Objekt1()), m_apObjekt2(new Objekt2()), m_apObjekt3(new Objekt3()) { }Wenn nun bei der Objektanlage irgendeines Teilobjektes eine Exception auftritt, so werden alle vorherigen gelöscht, und der Konstruktor erstellt kein Objekt (sprich: kein Objekt oder ein Konsistentes).
Versuch das mal ohne Exceptionhandling mit wenigen Codezeilen sinnvoll nachzubauen (noch dazu wenn vielleicht noch mehr Teilobjekte dazukommen).
cu André
-
ich bin kein fan von exceptions.
try { // gewaltiger, ellenlanger code } catch(...){} // weiter gehtssie verleiten zu lazy coding. gedanken darüber machen, ob auch alles klappt? input überprüfen? ach egal, wenn was schief geht, wird schon irgendwo ne exception fliegen, die man ja abfangen kann.
-
Maffe001 schrieb:
[Edit]
...Ich wollte die Exceptionvariante nicht kritisieren oder meine als die bessere hinstellen....Das war mir klar ... aber ich wollte Deine Variante kritisieren und die Exceptionvariante als die bessere hinstellen...

Was hast Du gegen exceptions ? Die sind genau für diesen Fall gemacht.
Ach ja: D.h. Du fragst auch bei printf() immer den Returncode ab ?
Gruß,
Simon2.