Geschwindigkeit bei geschachtelten try



  • Hallo,

    in einem Programm verwende ich exceptions in teilweise tiefgeschachtelten try/catch -Konstruktionen, aber ich habe ein Geschwindigkeitsproblem und überlege, ob ich dies lösen kann, indem ich mir was anderes einfallen lasse, als try/catch.

    Die Frage ist nun, ob viele ineinander geschachtelte try/catch langsamer sind als nur ein try/catch.

    // Variante A
    
    try 
    {
       // Tu was
    }
    catch(...)
    {
       // Ein richtiger runtime error
    }
    
    // Variante B
    
    try
    {
       // Tu was
       try
       {
          //Tu was anderes
          throw eA() ;
       }
       catch( eA& x )
       {
           // Korrigiere etwas
       }
    }
    catch(...)
    {
       // Ein richtiger runtime error
    }
    

    Ist also Variante B langsamer, weil es dort zwei try/catch abzuarbeiten gibt?
    ( Zeitaufwand für "// Korrigiere etwas" braucht nicht berücksichtigt zu werden, da ich den sowieso irgendwie implementieren muss.)



  • Ich habe mal gelesen (ich glaube es war im Buch von Stroustrup), dass Exception-Handling zumindest theoretisch ohne grosse Performanceeinbussen (soll heissen weniger als ein Function-call) implementiert werden kann. Und selbst wenn nicht, der Preis, welchen man für die Funktionalität bezahlt, ist mehr als angemessen. Stell dir vor, dass du auf jeder Zeile deine if s hinschreibst, welche dann auf mögliche Fehler testen sollen. Diese Variante wäre vermutlich teurer als Exceptions.

    Was mich eher beunruhigen würde als die Kosten von Exceptions wäre die Tatsache, dass du soviele verschachtelte try - catch -Blöcke hast; insbesondere wenn diese wirklich so wie du in deinem Beispiel B lokal innerhalb einer Funktion verschachtelt hast. Normalerweise deutet sowas auf einen Designfehler hin - zu viele Exceptions werden geworfen bei jeder Gelegenheit. Vielleicht solltest du dir deshalb überlegen, wann Exceptions wirklich nötig sind, und wann ein Rückgabewert à la false die bessere Variante ist. Exceptions sollten, wie der Name ja bereits dezent andeutet, nur in Ausnahmefällen geworfen werden.

    Abgesehen davon würde ich bei Performanceproblemen sicherlich nicht zuerst an C++-Sprachfeatures zurückschrauben, sondern versuchen, die Algorithmen zu optimieren. Das bringt normalerweise mehr und ist auch nachhaltiger 😉



  • Danke für die Antwort.

    wäre die Tatsache, dass du soviele verschachtelte try-catch-Blöcke hast; insbesondere wenn diese wirklich so wie du in deinem Beispiel B lokal innerhalb einer Funktion verschachtelt hast.

    Die Beispiele waren nur um den Sachverhalt zu verdeutlichen, was ich mit "verschachtelten try/catch" meine. In Wirklichkeit geht es darum, dass ich eine Baumstruktur aufbaue und jeweils eine try/catch um den Code des Constructors lege:

    CLASS_A::CLASS_A( ..., eA **ppxeA_GeworfeneException ) 
    {
       try
       {
          throw eA();
       }
       catch( eA& ea )
       {
          *ppxeA_GeworfeneException  = new eA() ;
       }
    }
    

    So wird keine exception aus dem Constructor "hinaus"geworfen, also das Object wirklich erstellt.

    Die aufrufende Funktion reagiert darauf, dass *ppxea_GeworfeneException != null ist, und zerstört das Object, in dessen Constructor eine exception geworfen wurde (so stelle ich sicher, dass der Destructor aufgerufen wird).

    try
    {
       CLASS_A *pxA = new CLASS_A(..., &pxeA_GeworfeneException ) ;
    
       if( pxeA_GeworfeneException != NULL )
       {
          delete pxA ;
          delete pxeA_GeworfeneException ;
          throw eA() ;
       }
    }
    catch( eA& ea )
    {
       // reagiere
    }
    

    Die Verschachtelung ergibt sich also aus der Baumstruktur und kann daher sehr tief sein.

    Was haltet Ihr von diesem Design? Gibt es eine bessere Möglichkeit?



  • kannmichnichterinnern schrieb:

    Gibt es eine bessere Möglichkeit?

    Verwende RAII und wirf im Konstruktor, wenn es keinen Sinn macht, das Objekt fertig zu erzeugen. Von allen bereits initialisierten Membern wird der Destruktor aufgerufen, selbst wenn der Destruktor des Objekts selbst nicht aufgerufen wird.



  • kannmichnichterinnern schrieb:

    Was haltet Ihr von diesem Design? Gibt es eine bessere Möglichkeit?

    Unschön; zu grosser Aufwand, zu kleiner Nutzen.

    LordJaxom schrieb:

    kannmichnichterinnern schrieb:

    Gibt es eine bessere Möglichkeit?

    Verwende RAII und wirf im Konstruktor, wenn es keinen Sinn macht, das Objekt fertig zu erzeugen. Von allen bereits initialisierten Membern wird der Destruktor aufgerufen, selbst wenn der Destruktor des Objekts selbst nicht aufgerufen wird.

    This 👍



  • LordJaxom schrieb:

    kannmichnichterinnern schrieb:

    Gibt es eine bessere Möglichkeit?

    Verwende RAII und wirf im Konstruktor, wenn es keinen Sinn macht, das Objekt fertig zu erzeugen. Von allen bereits initialisierten Membern wird der Destruktor aufgerufen, selbst wenn der Destruktor des Objekts selbst nicht aufgerufen wird.

    Ok, ich werde mir das mal angucken. Aber im Moment bin ich etwas in Zeitdruck und mir geht es vorrangig darum die Geschwindigkeit des Programms zu erhöhen. Besteht zumindest die MÖGLICHKEIT, dass RAII mir dabei hilft?
    (Ansonsten lass ich das für das nächste Projekt.)


Anmelden zum Antworten