2010-09-22 11 views
6

Bietet C++ eine Möglichkeit, etwas visuelles anzuzeigen, wenn eine unbehandelte Ausnahme auftritt?C++ unbehandelte Ausnahmen

Was ich tun möchte, ist so etwas wie assert(unhandled exception.msg()) zu machen, wenn es tatsächlich passiert (wie im folgenden Beispiel):

void foo() { 
    throw std::exception("Message!"); 
} 

int main() { 
foo(); 
} 

Ich erwarte, dass diese Art von Code nicht sofort zu beenden (weil Ausnahme nicht behandelte war), zeigen Sie lieber benutzerdefinierte Zusicherung Nachricht (Message! tatsächlich).

Ist das möglich?

+3

Warum setzen Sie nicht einfach einen try/catch-Block in 'main'? – GManNickG

+1

@GMan: Ein globaler Konstruktor oder Destruktor kann auch außerhalb von Main werfen. Für den Destruktorfall wird das Abwickeln möglicherweise nicht zum Hauptteil. – Potatoswatter

+0

@Potatoswatter: In der Tat war ich mehr mit seinem besonderen Beispiel beschäftigt. – GManNickG

Antwort

9

Es gibt keinen Weg durch den Standard spezifiziert die Nachricht tatsächlich von der nicht erfassten Ausnahme angezeigt werden soll. Auf vielen Plattformen ist es jedoch trotzdem möglich. Unter Windows können Sie SetUnhandledExceptionFilter verwenden und die C++ - Ausnahmebedingung extrahieren.Mit g ++ (entsprechenden Versionen sowieso) kann die beenden Handler die abgefangene Ausnahme mit Code zugreifen wie:

void terminate_handler() 
    { 
     try { throw; } 
     catch(const std::exception& e) { log(e.what()); } 
     catch(...) {} 
    } 

und in der Tat g ++ 's Standard beenden Handler tun etwas ähnlich. Sie können den Terminierungshandler mit set_terminate setzen.

Kurz gesagt, es gibt keine generische C++ Möglichkeit, aber es gibt Möglichkeiten, die von Ihrer Plattform abhängen.

+0

Ich mag das. Der Standard erfordert dies möglicherweise nicht ausdrücklich, aber es besagt, dass eine Ausnahme nur deaktiviert wird, wenn der Block, der sie abfängt, austritt. Da dies vor dem Beenden nicht passieren kann, sollte dieses portabel oder zumindest zu allem nach vorne kompatibel sein. Derselbe Trick sollte mit "Unerwartetem" funktionieren, und das würde eine Diagnose für illegales Abrollen ermöglichen. – Potatoswatter

+0

Es kann auch Ausnahmen abfangen, die von globalen Konstruktoren und Destruktoren ausgelöst werden, was ein catch-Block in 'main' nicht kann. – Potatoswatter

+0

@Potatoswatter Ich habe mindestens ein Setup gesehen, bei dem dieser Trick nicht wirklich funktioniert, ich behaupte nicht, genug Kenntnisse über den Standard (und die anderen Dinge, die wir mit der Ausnahmebehandlung machten) zu haben, um den einen oder den anderen zu sagen andere, aber ich weiß, dass es unter Linux mit einem modernen gcc funktioniert. –

1

Wenn ich Ihre Frage richtig lese, fragen Sie, ob Sie throw überladen können (indem Sie ihr Standardverhalten ändern), damit es etwas Benutzerdefiniertes tut. Nein, das kannst du nicht.

Edit: da Sie hartnäckig :) sind, ist hier eine schlechte Idee ™:

#include <iostream> 
#include <stdlib.h> 
#include <windows.h> 

void monkey() { 
    throw std::exception("poop!"); 
} 

LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *lpTopLevelExceptionFilter) { 
    std::cout << "poop was thrown!" << std::endl; 
    return EXCEPTION_EXECUTE_HANDLER; 
    } 

int main() { 
    SetUnhandledExceptionFilter(&MyUnhandledExceptionFilter); 
    monkey(); 
    return 1; 
} 

Auch dies ist eine sehr schlechte Idee, und es ist offensichtlich plattformabhängig, aber es funktioniert.

+0

Nicht wirklich "werfen". Ich möchte das Standardverhalten ändern, wenn eine nicht behandelte Ausnahmesituation auftritt. –

+0

Also im Grunde, wenn Sie eine unbehandelte Ausnahme "werfen": -P –

6

Microsoft Visual C++ ermöglicht es Ihnen, nicht behandelte C++ - Ausnahmen like this zu haken. Dies ist standard STL behaviour.

Sie legen einen Handler über einen Anruf auf set_terminate fest. Es wird empfohlen, dass Ihr Handler nicht viel arbeitet und dann das Programm beendet, aber ich sehe nicht, warum Sie etwas über eine Assert nicht signalisieren konnten - obwohl Sie nicht auf die Ausnahme zugreifen können, die das Problem verursacht hat.

+1

Der Terminator-Handler sollte nicht geltend machen. Es könnte 'printf' (oder besser, nur' write (2) 'in' STDERR_FILENO') schreiben und den terminate_handler aufrufen, den er ersetzt hat. Siehe auch Logans Antwort und Diskussion darüber, warum die Ausnahme zu diesem Zeitpunkt noch zugänglich sein sollte. – Potatoswatter

+0

@Potatoswatter - ist Ihre Aussage unter allen Umständen anwendbar - mit anderen Worten wäre es möglich zu behaupten, aber nicht empfohlen? Vielen Dank. –

+0

Es ist immer möglich, zu bestätigen, aber eine der Handler-Funktionen wird empfohlen, den zuvor installierten Handler abzurufen. – Potatoswatter

4

Wenn Sie Windows verwenden, ist eine gute Bibliothek für die Behandlung nicht behandelter Ausnahmen und Abstürze CrashRpt. Wenn Sie es manuell tun möchten, können Sie auch use the following I wrote in this answer.

+0

+1 für mehr expansive Antwort auf eine enge q –

4

denke ich, die Sie von einer Catch-all-Anweisung profitieren würden wie folgt:

int main() { 
try { 
    foo(); 
catch (...) { 
    // Do something with the unhandled exception. 
} 
} 
+4

Es ist erwähnenswert, dass die Ausnahme selbst ist nicht verfügbar für Introspektion in dieser Methode. Das liegt daran, dass Sie möglicherweise keine "std :: exception" -Instanz werfen, C++ erlaubt Ihnen, einen beliebigen Wert zu werfen, wie zum Beispiel ein "int" oder was auch immer. Sie können dies umgehen, indem Sie auch einen 'catch (std :: exception & e)' vor dem 'catch (...)' oder einen anderen Typ, den Sie fangen möchten, haben. – SingleNegationElimination

+0

Ein guter Punkt in der Tat. –

+0

Unter Windows muss man vorsichtig sein mit der (...) fangen strukturierten Ausnahme intern geworfen (zB Zugriffsverletzungen). Es kann gefährlich sein, die Ausführung unter diesen Bedingungen fortzusetzen. – seand

1

Ja, das ist möglich. Hier gehen Sie:

#include <iostream> 
#include <exception> 

void foo() 
{ 
    throw std::exception("Message!"); 
} 

int main() 
{ 
    try 
    { 
    foo(); 
    } 
    catch (std::exception& e) 
    { 
    std::cout << "Got exception: " << e.what() << std::endl; 
    } 

    return 0; 
} 
0

die C++ Standard ist der Handler beenden - wie andere gesagt haben

Wenn Sie nach besserer Rückverfolgbarkeit sind für wirft dann ist es das, was wir tun

Wir haben einen Makro Wurf Das protokolliert den Dateinamen und die Zeilennummer sowie die Nachricht und wirft dann. Es dauert eine varargs Nachricht im printf-Stil.

Throw(proj::FooException, "Fingle %s unable to process bar %d", fingle.c_str(), barNo); 

ich ein nettes Lognachricht

Throw FooException from nargle.cpp:42 Fingle barf is unable to process bar 99 
+1

Es gibt zwei Probleme mit diesem. Erstens fügt es den abgefangenen Ausnahmen zusätzliche Verarbeitung hinzu. Dies ist kein großes Problem, denn wenn es genug ist, dass der Overhead (oder das Rauschen im Protokoll) ein Problem darstellt, sollten Sie sowieso keine Ausnahmen für diesen Fall verwenden. Das zweite Problem ist ein eher praktisches Problem. Wenn Ausnahmebedingungen auftreten, kann die zusätzliche Verarbeitung ebenfalls fehlschlagen. Die Vorabzuweisung von Puffern für Fehlermeldungen kann hilfreich sein, aber letztendlich müssen Sie sicherstellen, dass Sie vor Fehlern während der Fehlerberichterstattung schützen. –

+0

seit es mich wirft (nicht die Laufzeit) Ich bin nicht in katastrophalen (kein Speicher, kein Stapel, toter Haufen) Modus, so dass der Handler funktioniert. Wenn nicht, dann bin ich sowieso tot. Ich benutze diese Technik in sehr großen kommerziellen Unternehmensprodukten (100s kloc) - ohne Probleme. Ich kann den Logging-Level einstellen, um Overhead zu unterdrücken – pm100

0

Wenn Sie wirklich daran interessiert sind, was passiert ist, damit Ihr Programm fehlschlägt, können Sie das Prozessabbild in einem Post-Mortem-Debugger untersuchen. Die genaue Technik variiert ein wenig von OS zu OS, aber der grundlegende Zug besteht darin, zuerst Core-Dumping zu aktivieren und dein Programm mit Debug-Symbolen zu kompilieren. Sobald das Programm abstürzt, wird das Betriebssystem seinen Speicher auf die Festplatte kopieren, und Sie können dann den Status des Programms zum Zeitpunkt des Absturzes untersuchen.

Verwandte Themen