Fehlerhandling Goto Label?



  • Hallo Forum,

    in einer Funktion werden andere Funktionen aufgerufen. Diese geben einen int zurück. Wenn der int negativ ist muss ich bestimmte Aufräumfunktionen aufrufen und bestimmte Dinge freigeben. Wie macht man das?

    1. Nach jeder Funktion den RetVal überprüfen und bei Fehler aufräumen? -> Es sammeln sich die Aufräumaufrufe bei den hinteren Funktionen. Auerdem doppelter Code.

    if (myFunc1(1)<1)
    delete a;
    
    if (myFunc2(1)<1) {
    delete a;
    delete b;
    }
    ...
    

    2. Den Code in eine TryCatch Klausel einfangen und bei negativen Rückgabewert einen Fehler werfen. -> Die Objekte müssen Funktionsglobal deklariert werden, damit sie auch im Catch Block freigegeben werden können.

    myclass *bob;
    
    try {
    if (myfunc(bob)<1)
    throw -1;
    } catch {
    delete bob;
    }
    

    3. Anstatt des throw ein goto zum Funktionsende. -> Goto keine Deklarationen oder Initialisatoren überspringen.

    if (myfunc(1)<1)
    goto CleanUp;
    // Hier darf nichts deklariert oder initialisiert werden.
    CleanUp:
    delete bob;
    

    Alle drei Möglichkeiten sind bescheiden. Gibt es bessere Möglichkeiten?



  • Wie wär's mit std::auto_ptr?



  • Sobald irgendwo Exceptions fliegen können verwendet man sowieso am besten Guards (eben sowas wie std::auto_ptr), so dass garkein explizites "Wegputzen" mehr notwendig ist. In dem Fall kann man dann einfach "if (int error = blubb()) return error;" schreiben.

    Und natürlich gibt es noch eine andere Möglichkeit: "nested if" Orgien zu bauen. Vorteil gegenüber deiner Version 1 ist dass man keine Aufräumarbeiten wiederholen muss, und von oben nach unten gelesen "Arbeit" nicht mit "aufräumen" vermischt. Allerdings ist es potthässlich sobald mal mehr als 2 oder 3 Ebenen zusammenbekommt.



  • Ich arbeite gerade an dem WMI Beispiel von -King- da muß ich am Ende CoUninitialize() aufrufen:
    http://www.c-plusplus.net/forum/viewtopic-var-p-is-92750.html#92750

    Die AutoPointer sind in diesen Fall keine optimale Lösung. Die geschachtelten If Anweisungen sind unübersichtlich. Wenn ich longjmp benutze werde ich gehängt *g*
    http://en.wikipedia.org/wiki/Longjmp

    Hmhm. In diesen Fall werde ich die Vorlage von King übernehmen. Aber richtig optimal ist keine Lösung.



  • Mokka schrieb:

    Ich arbeite gerade an dem WMI Beispiel von -King- da muß ich am Ende CoUninitialize() aufrufen:

    So was lässt sich prima in einer Klasse kapseln, die das dann eben in ihrem Destruktor tut. Das gleiche kann für die Interfacezeiger und den BSTR tun. Dafür gibt es sogar schon fertige Klassen.

    Die AutoPointer sind in diesen Fall keine optimale Lösung.

    Wieso nicht?



  • Den Autopointer könnte ich verwenden um die std::string Objekte zu löschen, aber nicht um CoUninitialize() aufzurufen. Es sei denn ich packe alles in eine Klassen. Dann muß ich aber wieder Klassenvariablen definieren um im Destruktor die Aufräumarbeit zu machen.



  • Mokka schrieb:

    Dann muß ich aber wieder Klassenvariablen definieren um im Destruktor die Aufräumarbeit zu machen.

    Und was ist so schlimm daran? Die Klasse mußt du einmal schreiben und kannst sie dann immer wieder verwenden. Und in der Anwendung reicht es aus, ein Objekt am Funktionsanfang anzulegen (und dann darauf zu warten, daß es aus dem Scope fällt).



  • Ich möchte nicht für jeden Schnipsel eine extra Klasse machen. Wenn ich mehr mit WMI machen möchte ist es aber überlegenswert.



  • Mokka schrieb:

    Ich möchte nicht für jeden Schnipsel eine extra Klasse machen.

    Du kannst dir aussuchen, ob du für jede einzelne Ressource Aufräumarbeit verrichtest (und das u.U. mehrfach, je nach Verschachtelung), oder ob du für jede Art, Ressourcen freizugeben, einmal eine Klasse schreibst, und damit auch gleich noch Exceptionsicherheit obendrauf bekommst.

    Und wie gesagt, CComPtr und CComBSTR gibt's schon.


Anmelden zum Antworten