problems - try catch except c++




Verringert try-catch-Block die Leistung (4)

Diese Frage hat hier bereits eine Antwort:

Dieser link besagt,

Um Ausnahmen abzufangen, müssen wir einen Teil des Codes unter die Ausnahmeprüfung stellen. Dies geschieht, indem dieser Teil des Codes in einen try-Block eingeschlossen wird. Wenn innerhalb dieses Blocks ein außergewöhnlicher Umstand auftritt, wird eine Ausnahme ausgelöst, die das Steuerelement an den Ausnahmebehandler überträgt. Wenn keine Ausnahme ausgelöst wird, wird der Code normal fortgesetzt und alle Handler werden ignoriert.

Bedeutet dies, dass ein Testblock die Leistung aufgrund der zusätzlichen Aufgabe "Inspektion" während der Laufzeit reduziert?


Es hängt wirklich vom spezifischen Compiler ab.

Wenn der Compiler es vorzieht, eine Exception zu betrachten, die eine wirklich außergewöhnliche Bedingung auslöst, können Sie ein Schema implementieren, bei dem Sie im Ausnahmefall keinen Overhead haben, aber im Falle einer Exception und / oder mehr Codegröße mehr Zeit benötigen .

Um einen Null-Overhead-Ansatz zu implementieren, können Sie feststellen, dass Sie in C ++ den Code nicht dynamisch ändern können. Sobald Sie wissen, was der Stack-Frame und die Rücksendeadresse sind, müssen die Objekte im Falle eines Unwindings zerstört werden Ausnahmebehandlungscode-Abschnitt. Der Code zum Auslösen einer Ausnahme könnte daher eine globale Tabelle aller Funktionsaufruf-Sites überprüfen, um zu entscheiden, was zu tun ist.

Auf der anderen Seite können Sie die Ausnahme schneller werfen, indem Sie die Liste der explizit zu vernichtenden Objekte und die Adresse des Code für die Ausnahmebehandlung während der normalen Ausführung vorbereiten. Dadurch wird der reguläre Code langsamer, aber die Ausnahmebehandlung wird schneller und auch der Code wird etwas kleiner.

Leider gibt es in C ++ keinen Standardweg, um die Exception-Unterstützung komplett aufzugeben, daher muss etwas auf diese Möglichkeit geachtet werden: Die Standard-Library löst Exceptions aus und Code, der unbekannten Code aufruft (zB mit einem Funktionszeiger oder Aufruf einer virtuellen Methode) muss bereit sein, eine Ausnahme zu behandeln.


Es kommt darauf an. Für die Ausnahmebehandlung muss der Compiler etwas tun - andernfalls könnte er den Stack nicht abwickeln und so weiter. Das bedeutet, dass die Ausnahmebehandlung die Leistung verringert - auch wenn die Ausnahme nicht ausgelöst wird. Wie viel - das hängt von Ihrer Compiler-Implementierung ab.

Auf der anderen Seite müssen Sie sich selbst in Frage stellen: Wenn Sie Ihren Fehlerbehandlungscode selbst einfügen, wäre er dann wirklich schneller (messen Sie es - raten Sie nicht). Kann es genauso wie Ausnahmen machen (Ausnahmen können vom Client nicht ignoriert werden - Fehlercodes können - und sie können stapeln, welche Fehlercodes nicht möglich sind). Darüber hinaus kann der Code so geschrieben werden, dass er mit Ausnahmen wartungsfreundlicher ist.

Kurz: Wenn Ihr Code nicht sehr, sehr sehr sehr zeitkritisch ist, verwenden Sie Ausnahmen. Selbst wenn Sie sich dagegen entscheiden: Messen Sie zuerst. Eine Ausnahme von der Regel: Es ist eine schlechte Idee, Ausnahmen über Modulgrenzen hinweg oder in einem Destruktor auszulösen.


TL; DR NEIN , Ausnahmen sind normalerweise schneller auf dem nicht-außergewöhnlichen Pfad verglichen mit der Fehlercode-Behandlung.

Nun, die offensichtliche Bemerkung wird mit was verglichen?

Verglichen mit der Nichtbehandlung des Fehlers verringert es offensichtlich die Leistung; aber ist die Leistung die mangelnde Korrektheit wert? Ich würde argumentieren, dass es nicht ist, also lassen Sie uns annehmen, dass Sie im Vergleich zu einem Fehlercode mit einer if Anweisung überprüft haben.

In diesem Fall kommt es darauf an. Es gibt mehrere Mechanismen zum Implementieren von Ausnahmen. Tatsächlich können sie mit einem Mechanismus implementiert werden, der einer if Anweisung so nahe kommt, dass sie die gleichen Kosten (oder etwas höher) haben.

In C ++ verwenden jedoch alle großen Compiler (gcc führte es in der 4.x-Serie ein, MSVC verwendet es für 64-Bit-Code) nun das Zero-Cost-Exception-Modell. Wenn Sie dieses technische Paper lesen, mit dem Need4Sleep verknüpft ist, wird es als tabellengesteuerter Ansatz aufgeführt. Die Idee ist, dass Sie für jeden Punkt des Programms, der Sie werfen kann, in einer Seitentabelle einige Bits und Stücke registrieren, mit denen Sie die richtige Fangklausel finden können. Ehrlich gesagt ist es ein bisschen komplizierter als die älteren Strategien, aber der Name " Zero Cost" ergibt sich aus der Tatsache, dass es kostenlos ist, sollte keine Ausnahme ausgelöst werden. Vergleichen Sie dies mit einer Verzweigungsfehlvorhersage auf einer CPU. Auf der anderen Seite, wenn eine Ausnahme ausgelöst wird, ist die Strafe enorm, weil die Tabelle in einer kalten Zone gespeichert wird (also wahrscheinlich einen Hin- und Rückweg zum RAM oder schlechter) ... aber Ausnahmen sind außergewöhnlich, oder?

Zusammenfassend ist festzustellen, dass bei modernen C ++ - Compilern Ausnahmen auf Kosten von größeren Binärdateien schneller sind als Fehlercodes (aufgrund der statischen Tabellen).


Werfen Sie einen Blick auf Abschnitt 5.4 des Entwurfs des technischen Berichts zu C ++ Performance, der speziell den Overhead von try-catch-Anweisungen in C ++ behandelt.

Ein kleiner Auszug aus dem Abschnitt:

5.4.1.1.2 Zeitaufwand für den "Code" -Ansatz

• On entry to each try-block
    ♦ Commit changes to variables enclosing the try-block
    ♦ Stack the execution context 
    ♦ Stack the associated catch clauses 
• On exit from each try-block
    ♦ Remove the associated catch clauses 
    ♦ Remove the stacked execution context 
• When calling regular functions 
    ♦ If a function has an exception-specification, register it for checking 
• As local and temporary objects are created 
    ♦ Register each one with the current exception context as it is created 
• On throw or re-throw 
    ♦ Locate the corresponding catch clause (if any) – this involves some runtime check (possibly resembling RTTI checks) 
    If found, then: 
    destroy the registered local objects 
    check the exception-specifications of the functions called in-between 
    use the associated execution context of the catch clause 
    Otherwise: 
    call the terminate_handler6






try-catch