it-swarm.com.de

C++ fängt alle Ausnahmen ab

Gibt es ein C++ - Äquivalent von Java?

try {
    ...
}
catch (Throwable t) {
    ...
}

Ich versuche, Java/Jni-Code zu debuggen, der native Windows-Funktionen aufruft und die virtuelle Maschine immer mehr abstürzt. Der native Code erscheint im Komponententest einwandfrei und scheint nur bei Aufruf über jni abgestürzt zu sein. Ein generischer Ausnahmemechanismus würde sich als äußerst nützlich erweisen.

203
Obediah Stane
try{
    // ...
} catch (...) {
    // ...
}

fängt alle C++ - Ausnahmen ab, sollte aber als schlechtes Design betrachtet werden. Sie können den neuen current_exception-Mechanismus von C++ 11 verwenden. Wenn Sie jedoch nicht in der Lage sind, C++ 11 (ältere Codesysteme, die ein Neuschreiben erfordern) zu verwenden, haben Sie keinen benannten Ausnahmepunkt, um eine Nachricht oder einen Namen abzurufen . Sie können separate catch-Klauseln für die verschiedenen Ausnahmen hinzufügen, die Sie abfangen können, und nur alles unten abfangen, um eine unerwartete Ausnahmebedingung aufzuzeichnen. Z.B.:

try{
    // ...
} catch (const std::exception& ex) {
    // ...
} catch (const std::string& ex) {
    // ...
} catch (...) {
    // ...
}
294
Greg D

Jemand sollte hinzufügen, dass "Abstürze" im C++ - Code nicht erfasst werden können. Diese werfen keine Ausnahmen aus, tun aber alles, was ihnen gefällt. Wenn Sie sehen, dass ein Programm aufgrund einer Null-Zeiger-Dereferenzierung abstürzt, führt dies zu undefiniertem Verhalten. Es gibt keinen std::null_pointer_exception. Der Versuch, Ausnahmen zu fangen, wird da nicht helfen.

Nur für den Fall, dass jemand diesen Thread liest und meint, er könnte die Ursache für das Programmabsturz bekommen. Stattdessen sollte ein Debugger wie gdb verwendet werden.

123
try {
   // ...
} catch (...) {
   // ...
}

Beachten Sie, dass der ... in der catch eine echte Ellipsis ist, dh. drei Punkte.

Da C++ - Ausnahmen jedoch nicht notwendigerweise Unterklassen einer Klasse Exception sind, gibt es keine Möglichkeit, die Ausnahmevariable zu sehen, die ausgelöst wird, wenn dieses Konstrukt verwendet wird.

54
Greg Hewgill

So können Sie den Ausnahmetyp in catch(...) nach Bedarf zurückentwickeln (dies kann nützlich sein, wenn Sie Unbekanntes aus einer Bibliothek eines Drittanbieters einfangen) mit GCC:

#include <iostream>

#include <exception>
#include <typeinfo>
#include <stdexcept>

int main()
{
    try {
        throw ...; // throw something
    }
    catch(...)
    {
        std::exception_ptr p = std::current_exception();
        std::clog <<(p ? p.__cxa_exception_type()->name() : "null") << std::endl;
    }
    return 1;
}

und wenn Sie es sich leisten können, Boost zu verwenden, können Sie Ihre Fangsektion (außen) noch einfacher und möglicherweise plattformübergreifend gestalten

catch (...)
{
    std::clog << boost::current_exception_diagnostic_information() << std::endl;
}
44
bobah

es ist (in C++) nicht möglich, alle Ausnahmen auf tragbare Weise zu erfassen. Dies liegt daran, dass einige Ausnahmen keine Ausnahmen in einem C++ - Kontext sind. Dies beinhaltet Dinge wie Division durch Null Fehler und andere. Es ist möglich, herumzumachen und so die Möglichkeit zu haben, Ausnahmen zu werfen, wenn diese Fehler auftreten, aber es ist nicht einfach zu tun und sicherlich nicht leicht, auf tragbare Weise richtig zu werden.

Wenn Sie alle STL-Ausnahmen abfangen möchten, können Sie dies tun

try { ... } catch( const std::exception &e) { ... }

Damit können Sie e.what() verwenden, wodurch ein const char* zurückgegeben wird, der Ihnen mehr über die Ausnahme selbst sagen kann. Dies ist das Konstrukt, das dem Java-Konstrukt ähnelt, nach dem Sie am meisten gefragt haben.

Dies hilft nicht, wenn jemand dumm genug ist, um eine Ausnahme auszulösen, die nicht von std::exception erbt.

33
Clearer

Kurz gesagt, verwenden Sie catch(...). Beachten Sie jedoch, dass catch(...) grundsätzlich in Verbindung mit throw; verwendet werden soll:

try{
    foo = new Foo;
    bar = new Bar;
}
catch(...)       // will catch all possible errors thrown. 
{ 
    delete foo;
    delete bar;
    throw;       // throw the same error again to be handled somewhere else
}

Dies ist der richtige Weg, um catch(...) zu verwenden.

20
Mellester

es ist möglich, dies zu schreiben:

try
{
  //.......
}
catch(...) // <<- catch all
{
  //.......
}

Es besteht jedoch ein sehr nicht wahrnehmbares Risiko: Sie können die genaue Art des Fehlers nicht finden, der im try-Block ausgegeben wurde. Verwenden Sie diese Art von catch, wenn Sie sicher sind, dass das Programm unabhängig von der Art der Ausnahme ist muss auf die im catch-Block definierte Weise bestehen bleiben.

17
Infintyyy

Sie können verwenden 

catch(...)

aber das ist sehr gefährlich. In seinem Buch Debugging Windows erzählt John Robbins eine Kriegsgeschichte über einen wirklich bösen Bug, der durch einen catch (...) - Befehl maskiert wurde. Es ist viel besser, bestimmte Ausnahmen zu erfassen. Fangen Sie alles ab, was Sie Ihrer Meinung nach von Ihrem try-Block erwarten könnten, aber lassen Sie den Code eine Ausnahme höher werfen, wenn etwas wirklich Unerwartetes passiert.

16
John D. Cook

Lassen Sie mich das hier nur erwähnen: das Java

try 
{
...
}
catch (Exception e)
{
...
}

nICHT alle Ausnahmen fangen! Ich habe tatsächlich so etwas schon einmal passiert, und es ist wahnsinnig provozierend; Ausnahme ergibt sich aus Throwable. Um alles zu fangen, wollen Sie NICHT Ausnahmen fangen. Du willst Throwable fangen.

Ich weiß, es klingt pingelig, aber wenn Sie mehrere Tage versucht haben, herauszufinden, wo die "nicht erfasste Ausnahme" im Code herkam, der von einem try ... catch (Ausnahme e) -Block umgeben war, kommt er mit Sie.

12
Paul Sonier

Nun, wenn Sie alle Ausnahmen erfassen möchten, um beispielsweise einen Minidump zu erstellen ...

Jemand hat die Arbeit unter Windows gemacht.

Siehe http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus .__ In dem Artikel erklärt er, wie er herausgefunden hat, wie er Ausnahmen aller Art einfangen kann liefert Code, der funktioniert.

Hier ist die Liste, die Sie fangen können:

 SEH exception
 terminate
 unexpected
 pure virtual method call
 invalid parameter
 new operator fault 
 SIGABR
 SIGFPE
 SIGILL
 SIGINT
 SIGSEGV
 SIGTERM
 Raised exception
C++ typed exception

Und die Verwendung: CCrashHandler ch; Ch.SetProcessExceptionHandlers (); // Tun Sie dies für einen Thread ch.SetThreadExceptionHandlers (); // für jeden Thred


Standardmäßig wird ein Minidump im aktuellen Verzeichnis erstellt (crashdump.dmp).

6
Aftershock

Ein allgemeiner Mechanismus zum Ausnahmefangen würde sich als äußerst nützlich erweisen.

Zweifelhaft. Sie wissen bereits, dass Ihr Code fehlerhaft ist, weil er abstürzt. Essensausnahmen können dies überdecken, aber das führt wahrscheinlich nur zu noch böseren, subtileren Fehlern. 

Was Sie wirklich wollen, ist ein Debugger ...

3
Shog9
  1. Können Sie Ihre JNI-basierte Java-Anwendung über ein Konsolenfenster ausführen (über eine Java-Befehlszeile starten), um zu sehen, ob ein Bericht darüber vorliegt, was möglicherweise vor dem Absturz der JVM entdeckt wurde. Wenn Sie direkt als Java-Fensteranwendung ausgeführt werden, fehlen möglicherweise Meldungen, die angezeigt würden, wenn Sie stattdessen von einem Konsolenfenster aus ausgeführt wurden.

  2. Zweitens: Können Sie Ihre JNI DLL -Implementierung stubben, um zu zeigen, dass Methoden in Ihrer DLL von JNI eingegeben werden, kehren Sie ordnungsgemäß zurück usw.? 

  3. Nur für den Fall, dass das Problem in einer falschen Verwendung einer der Methoden der JNI-Schnittstelle aus dem C++ - Code liegt, haben Sie überprüft, dass einige einfache JNI-Beispiele Ihr Setup kompilieren und damit arbeiten? Ich denke insbesondere daran, die Methoden der JNI-Schnittstelle zu verwenden, um Parameter in native C++ - Formate zu konvertieren und Funktionsergebnisse in Java-Typen umzuwandeln. Es ist nützlich, diese zu stubben, um sicherzustellen, dass die Datenkonvertierungen funktionieren und Sie bei den COM-ähnlichen Aufrufen in der JNI-Schnittstelle nicht durcheinander geraten.

  4. Es gibt andere Dinge, die Sie überprüfen sollten, aber es ist schwer, etwas vorzuschlagen, ohne mehr darüber zu wissen, was Ihre nativen Java-Methoden sind und was die JNI-Implementierung zu tun versucht. Es ist nicht klar, dass das Abfangen einer Ausnahme von der C++ - Codeebene mit Ihrem Problem zusammenhängt. (Sie können die JNI-Schnittstelle verwenden, um die Ausnahme als Java-Schnittstelle erneut zu starten, aber aus den von Ihnen angegebenen Informationen ist nicht klar, dass dies helfen wird.)

2
orcmid

Für das eigentliche Problem, dass Sie ein Programm nicht ordnungsgemäß debuggen können, das JNI verwendet (oder der Fehler nicht erscheint, wenn Sie es unter einem Debugger ausführen):

In diesem Fall ist es oft hilfreich, Java-Wrapper um Ihre JNI-Aufrufe hinzuzufügen (dh alle systemeigenen Methoden sind privat und Ihre öffentlichen Methoden in der Klasse rufen sie auf), die einige grundlegende Sicherheitsüberprüfungen durchführen (prüfen, ob alle "Objekte" freigegeben sind und "Objekte".) werden nicht nach dem Freigeben) oder nach der Synchronisation verwendet (synchronisieren Sie einfach alle Methoden von einer DLL zu einer einzelnen Objektinstanz). Lassen Sie die Java-Wrapper-Methoden den Fehler protokollieren und eine Ausnahme auslösen.

Dies hilft oft, den echten Fehler (der überraschenderweise meistens im Java-Code enthalten ist, der nicht der Semantik der aufgerufenen Funktionen gehorcht, die einige unangenehme Double-Free oder Ähnliches verursachen) leichter als das Versuchen eines Debugging eines massiv parallelen Java-Programms in einem nativer Debugger ...

Wenn Sie die Ursache kennen, behalten Sie den Code in Ihren Wrapper-Methoden, um ihn zu vermeiden. Es ist besser, wenn Ihre Wrapper-Methoden Ausnahmen auslösen, als dass Ihr JNI-Code die VM zum Absturz bringt ...

1
mihi

Nun, das hängt wirklich von der Umgebung des Compilers ab Gcc kann diese nicht einfangen

Die Schlussfolgerung zu Abstürzen lautet daher, dass dies von der Qualität Ihrer Entwicklungsumgebung abhängt.

Die Spezifikation von C++ .__ sagt, dass catch (...) alle Ausnahmen abfangen muss, dies gilt jedoch nicht in allen Fällen.

Zumindest von dem, was ich versucht habe.

0
Jan