Konstruktor auch ohne Erfolg realisierbar?



  • 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 -> delete

    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 = 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 = NULL

    so 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 gehts
    

    sie 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.



  • thordk schrieb:

    ...sie verleiten zu lazy coding....

    Inwieweit das ? 😕
    Ich würde eher sagen: Mit exceptions kann man sich auf das Wesentliche konzentrieren ... versuch mal, ohne exceptions "exceptions safety" (= ein Kriterium einer stabilen Schnittstelle) umzusetzen ... da wirst Du Dir die Finger brechen - und letztlich eine Art exceptions (nur mit mehr Overhead) selbst programmieren.

    Gruß,

    Simon2.



  • thordk schrieb:

    sie verleiten zu lazy coding.

    Wenn du ohne Exceptions arbeitest, ist das noch schlimmer. Vor allem wird dich niemand darauf aufmerksam machen, wenn du vergessen hast, einen Fehlerwert zu überprüfen (und was dein Programm in einem fehlerhaften Zustand macht, kann dir niemand sagen) - Exceptions fliegen dir ziemlich lautstark um die Ohren, wenn du versuchst, sie zu ignorieren.



  • @simon2:

    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. Vielleicht ist diese Einstellung wirklich etwas blauäugig.

    Hmpf, ich seh schon. Ich werd meine Einstellung zu Exceptions überdenken müssen. Allerdings bin ich immernoch der Meinung, dass man bei Objekten, die man nicht richtig initialisiert bekommt auch weiterhin mit Rückgabewerten arbeiten kann. Wenn euch jetzt ein Gegenbeispiel einfällt, dass sich nur mit Exceptions behandeln lässt, dann immer her damit. 🙂

    [Edit]Ui, ich hab grad den Beitrag von asc entdeckt. Sorry, ging in der Aufregung unter. Dann vergesst, was ich gesagt habe. Die Gründe leuchten ein. Gut ich werde nochmal darüber meditieren und mich mit Exceptions anfreunden. :D[/Edit]



  • 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.



  • 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?


Anmelden zum Antworten