Problem mit Exceptions im Konstruktor



  • Hallo,

    der Konstruktor einer meiner Klassen kann eine Exception werfen.
    Jetzt habe ich aber ein Problem wenn ich diese Exception abfangen will.
    Dazu folgendes Beispiel:

    try
    {
       Brief b(".\\brief.xml");
    }
    catch (string& e)
    {
        cout << e;
    }
    
    b.tuWas();
    

    Das funktioniert natürlich nicht, weil er bei tuWas() b überhaupt nicht kennt.
    Aber wie könnte ich das dann lösen?
    tuWas mit in den catch-Block? Dann müsste da aber noch mehr rein und ich wüsste irgendwann nicht mehr, wer da eine Exception geworfen hat.
    b vorher schon mit Brief b; deklarieren? Dann würde ja zwei mal ein Konstruktor von Brief aufgerufen werden, was ja auch unbedingt nicht sein muss.

    Wie löst ihr das?



  • Wann soll denn tuWas() ausgeführt werden? Natürlich nur wenns Brief-Instanzierung erfolgreich war.

    try
    {
       Brief b(".\\brief.xml");
       b.tuWas();
    }
    catch (string& e)
    {
        cout << e;
    }
    


  • Wenn ich das aber so mache wie dues ovrgeschlagen hast, dann müsste ich mein
    ganzes Programm in den try Block schreiben (weil das ganze Programm mit diesem
    Brief-Objekt interagiert) und dann fange ich vielleicht auch Exceptions die nicht
    vom Konstruktor geworfen werden, was ja auch nicht unbedingt so toll ist.



  • Hi,

    pack es doch auf den Heap.

    Brief* b = NULL;
    try {
        b = new Brief(".\\brief.xml");
    } catch (string& e) {
        cout << e;
        delete b;
    }
    
    b->tuWas();
    // ...
    delete b;
    

    musst nur mit der zerstörung deines Objektes aufpassen (oder Smart-Pointer verwenden)



  • Es gibt kein b, wenn der Konstruktor geworfen hat. Jeglicher Zugriff auf b wäre undefiniert. Die Variante über den Heap ermöglicht auch nur, den Zeiger danach anzusprechen. Der zeigt aber, wenn der Konstruktor geworfen hat, ins Nirvana.



  • martl schrieb:

    Wenn ich das aber so mache wie dues ovrgeschlagen hast, dann müsste ich mein
    ganzes Programm in den try Block schreiben (weil das ganze Programm mit diesem
    Brief-Objekt interagiert) und dann fange ich vielleicht auch Exceptions die nicht
    vom Konstruktor geworfen werden, was ja auch nicht unbedingt so toll ist.

    Das ist auch so üblich, schließlich soll der Anwender eine schöne Fehlermeldung sehen wenn was schiefgeht und keine Windows-Fehlermeldung weil eine ungefangene Excpetion das Programm terminiert hat.

    Und du hast dein Problem auch nur weil du als Exception-Objekte std::string benutzt würdest du verschiedene Exceptions von std::exception und Unterklassen ableiten und dir so eine Exceptionhierarchie aufbauen wäre das alles gar kein Problem.



  • Generell gilt, dass man Exceptions nur dort fangen soll, wo man sie auch reparieren kann. Wenn man sie nicht reparieren kann, sollen sie ruhig komplett durchrasseln, bis sie in der main gecatcht werden damit der nutzer vor der programmterminierung eine schöne Fehlermeldung sieht(wie Elite-Progger bereits sagte).

    Ausnahme sind hier die ganz bösen exceptions vom Betriebssystem wie out of memory, division durch null, etc.pp die sollten am besten nicht gefangen werden, weil die debugger dann schön viele Informationen liefern können(ausnahme ist im release mode, wenn ein backtrace tool im programm integriert ist).

    Und untersteh dich, irgendwo einen catch(...) block zu verwenden, die sind böse 😉


  • Mod

    LordJaxom_nl schrieb:

    Die Variante über den Heap ermöglicht auch nur, den Zeiger danach anzusprechen. Der zeigt aber, wenn der Konstruktor geworfen hat, ins Nirvana.

    Genaugenommen ist es immer noch ein Nullpointer.



  • martl schrieb:

    Wenn ich das aber so mache wie dues ovrgeschlagen hast, dann müsste ich mein
    ganzes Programm in den try Block schreiben (weil das ganze Programm mit diesem
    Brief-Objekt interagiert) und dann fange ich vielleicht auch Exceptions die nicht
    vom Konstruktor geworfen werden, was ja auch nicht unbedingt so toll ist.

    dann halt so:

    try 
    { 
       Brief b(".\\brief.xml"); 
       try 
       { 
          // rest vom programm
          b.tuWas(); 
       }
       catch (...) // bzw. was halt geworfen werden kann
       {
          // exception aus "rest vom programm"
       }
    } 
    catch (string& e) 
    { 
        cout << e; 
    }
    

    was auf jeden fall nicht geht ist ein objekt welches du nicht konstruiert hast zu verwenden. d.h. wenn 'Brief b(".\\brief.xml");' eine exception wirft kannst du b logischerweise nicht verwenden, da es b in dem fall nicht gibt.



  • otze schrieb:

    Und untersteh dich, irgendwo einen catch(...) block zu verwenden, die sind böse 😉

    Wie meinst du das jetzt?


Log in to reply