Frage

Ich arbeite derzeit daran, meiner OSS -Anwendung Ausnahmen und Ausnahmebehandlung hinzuzufügen. Ausnahmen waren von Anfang an die allgemeine Idee, aber ich wollte ein gutes Ausnahmebereich finden und ehrlich gesagt verstehen, dass C ++ -Ennahmebeheuerung Konventionen und Redewendungen ein bisschen besser verstehen, bevor ich anfing, sie zu verwenden. Ich habe viel Erfahrung mit C#/. Net, Python und anderen Sprachen, die Ausnahmen verwenden. Ich bin kein Unbekannter der Idee (aber weit weg von einem Meister).

In C# und Python erhält der Benutzer eine nette Stapelspur und im Allgemeinen viele sehr hilfreich Unbezahlte Debugging -Informationen. Wenn Sie an einer OSS -Anwendung arbeiten, ist es, wenn Benutzer diese Informationen in problematische Berichte einfügen, wenn Sie nur sagen, dass es mir schwierig ist, ohne das zu leben. Für dieses C ++ - Projekt bekomme ich "die Anwendung abstürzt" oder von fundierteren Benutzern "Ich habe X, Y und Z gemacht und dann ist es abgestürzt". Aber ich möchte auch diese Debugging -Informationen!

Ich habe bereits (und mit großer Schwierigkeit) meinen Frieden mit der Tatsache gemacht, dass ich nie eine plattformübergreifende und compiler-Art sehen werde relevante Information.

Und jetzt möchte ich das für meine unberechtigten Ausnahmen. Ich benutze Boost :: Ausnahme, und sie haben das sehr schön Diagnostic_information ThingAMAJIG, das den (unmangelierten) Funktionsnamen, die Datei, die Zeile und vor allem andere Ausnahmespezifische Informationen ausdrucken kann, die der Programmierer dieser Ausnahme hinzugefügt hat.

Natürlich werde ich mit Ausnahmen im Code handeln, wann immer ich kann, aber ich bin nicht so naiv zu glauben, dass ich ein paar nicht durchrutschen werde (natürlich ungewollt).

Ich möchte also meinen Haupteintrittspunkt in a wickeln try Block mit a catch Dies erstellt einen speziellen Dialog, der den Benutzer darüber informiert, dass in der Anwendung ein Fehler aufgetreten ist, wobei detailliertere Informationen angezeigt werden, wenn der Benutzer "mehr" oder "Debug -Info" oder was auch immer klickt. Dies würde die Zeichenfolge von Diagnostic_information enthalten. Ich könnte dann die Benutzer anweisen, diese Informationen in Ausgabeberichte einzufügen.

Aber ein nagendes Bauchgefühl sagt mir, dass es eine wirklich schlechte Idee ist, alles in einen Try -Block zu wickeln. Ist das, was ich dumm tun werde? Wenn es so ist (und auch wenn es nicht ist), was ist ein besserer Weg, um das zu erreichen, was ich will?

War es hilfreich?

Lösung

Wickeln Sie Ihren gesamten Code in einen ein try/catch Block ist A-OK. Es wird die Ausführung von irgendetwas darin zum Beispiel nicht verlangsamen. Tatsächlich haben alle meine Programme (ähnlich wie Code) dieses Framework:

int execute(int pArgc, char *pArgv[])
{
    // do stuff
}

int main(int pArgc, char *pArgv[])
{
    // maybe setup some debug stuff,
    // like splitting cerr to log.txt

    try
    {
        return execute(pArgc, pArgv);
    }
    catch (const std::exception& e)
    {
        std::cerr << "Unhandled exception:\n" << e.what() << std::endl;
        // or other methods of displaying an error

        return EXIT_FAILURE;
    }
    catch (...)
    {
        std::cerr << "Unknown exception!" << std::endl;

        return EXIT_FAILURE;
    }
}

Andere Tipps

In Main () einen Versuch/Catch -Block zu setzen, ist in Ordnung, es verursacht keine Probleme. Das Programm ist trotzdem tot mit einer ungehandelten Ausnahme. Es wird überhaupt nicht hilfreich sein, um die wichtige Stapelspur zu erhalten. Diese Informationen sind Gonzo, wenn der Catch -Block die Ausnahme fängt.

Eine C ++ - Ausnahme zu fangen ist auch nicht sehr hilfreich. Die Chancen, dass das Programm auf einer Ausnahme stirbt, die aus STD :: Ausnahme abgeleitet ist, sind ziemlich schlank. Obwohl es passieren könnte. In einer C/C ++ - App ist der Tod aufgrund von Hardwareausnahmen viel wahrscheinlicher, wobei AccessViolation numero uno ist. Wenn Sie diese eingefangen haben, müssen Sie die Schlüsselwörter __try und __except in Ihrer Main () -Methode. Auch hier ist nur sehr wenig Kontext verfügbar, Sie haben im Grunde nur einen Ausnahmegescode. Ein AV teilt Ihnen auch mit, welcher genaue Speicherort die Ausnahme verursacht hat.

Dies ist übrigens nicht nur ein plattformübergreifendes Problem, Sie können auf keiner Plattform eine gute Stapelspur erhalten. Es gibt keine zuverlässige Möglichkeit, den Stapel zu laufen, es gibt zu viele Optimierungen (wie Framepointer -Unterlassung), die dies zu einer gefährlichen Reise machen. Es ist die C/C ++ -Heweg: Machen Sie es so schnell wie möglich, lassen Sie keine Ahnung, was passiert ist, wenn es aufbläst.

Was Sie tun müssen, ist diese Art von Problemen auf den C/C ++ -Heweg zu debuggen. Sie müssen einen Minidump erstellen. Es ist ungefähr analog zum "Core -Dump" von Old, einem Schnappschuss des Prozessbildes zum Zeitpunkt der Ausnahme. Damals haben Sie tatsächlich eine komplette Müllkippe des Kerns. Heutzutage ist es Fortschritte, es ist "mini", etwas notwendig, weil ein kompletter Kernmüll fast 2 Gigabyte dauern würde. Es funktioniert tatsächlich ziemlich gut, um den Programmstatus zu diagnostizieren.

Unter Windows, das mit dem Aufruf von setunhandleDexceptionFilter () beginnt, geben Sie einen Rückruffunktionszeiger für eine Funktion, die ausgeführt wird, wenn Ihr Programm auf einer unberechtigten Ausnahme stirbt. Jede Ausnahme, C ++ sowie SEH. Ihre nächste Ressource ist dbgHelp.dll, die in den Debugging -Tools für Windows Download verfügbar ist. Es hat einen Einstiegspunkt namens Minidumpwrititedump (), es schafft einen Minidump.

Sobald Sie die von Minidumpwritedump () erstellte Datei erstellt haben, sind Sie ziemlich golden. Sie können die .dmp -Datei in Visual Studio laden, fast wie ein Projekt. Drücken Sie F5 und VS für eine Weile weg, um .PDB -Dateien für die im Vorgang geladenen DLLs zu laden. Sie möchten den Symbolserver einrichten, das ist sehr Wichtig, um gute Stapelspuren zu bekommen. Wenn alles funktioniert, erhalten Sie eine "Debug -Pause" an genau dem Ort, an dem die Ausnahme ausgelöst wurde ". Mit einer Stapelspur.

Dinge, die Sie tun müssen, um dies reibungslos zu machen:

  • Verwenden Sie einen Build -Server, um die Binärdateien zu erstellen. Es muss die Debugging -Symbole (.pdb -Dateien) auf einen Symbolserver übertragen, damit sie beim Debuggen des Minidumps leicht verfügbar sind.
  • Konfigurieren Sie den Debugger, damit die Debugging -Symbole für alle Module finden können. Sie können die Debugging -Symbole für Windows von Microsoft erhalten. Die Symbole für Ihren Code müssen vom oben genannten Symbolserver stammen.
  • Schreiben Sie den Code, um die nicht behandelte Ausnahme zu fangen und den Minidump zu erstellen. Ich habe setunhandledexceptionFilter () erwähnt, aber der Code, der den Minidump erstellt, sollte nicht in dem Programm sein, das abgestürzt ist. Die Wahrscheinlichkeit, dass es den Minidump erfolgreich schreiben kann, sind ziemlich schlank, der Zustand des Programms ist unbestimmt. Das Beste, was Sie tun können, ist, einen "Schutzprozess" durchzuführen, der einen genannten Mutex im Auge behält. Ihr Ausnahmefilter kann den Mutex festlegen, der Wachmann kann den Minidump erstellen.
  • Erstellen Sie einen Weg für den Minidump, um von der Kundenmaschine auf Ihre übertragen zu werden. Wir nutzen den S3 -Service von Amazon dafür, Terabyte zu einem angemessenen Preis.
  • Drahieren Sie den Minidump -Handler in Ihre Debug -Datenbank. Wir verwenden JIRA, es verfügt über einen Web-Service, mit dem wir den Crash-Bucket mit derselben "Signatur" anhand einer Datenbank früherer Abstürze überprüfen können. Wenn es eindeutig ist oder nicht genügend Treffer hat, bitten wir den Crash -Manager -Code, den Minidump auf Amazon hochzuladen und den Fehler -Eintrag für Fehlerdatenbank zu erstellen.

Nun, das habe ich für die Firma getan, für die ich arbeite. Sehr gut geklappt, reduzierte es die Frequenz der Crash -Eimer von Tausenden auf Dutzende. Persönliche Nachricht an die Schöpfer der Open Source -FFDShow -Komponente: Ich hasse Sie mit einer Leidenschaft. Aber Sie stürzen unsere App nicht mehr ab! Bugger.

Nein, es ist nicht dumm. Es ist eine sehr gute Idee und kostet praktisch nichts zur Laufzeit, bis Sie natürlich eine unberechtigte Ausnahme treffen.

Beachten Sie, dass es bereits einen Ausnahmebehandler gibt, der Ihren Thread umwickelt, der vom Betriebssystem bereitgestellt wird (und eine andere von der C-Runtime, denke ich). Möglicherweise müssen Sie bestimmte Ausnahmen an diese Handler weitergeben, um korrektes Verhalten zu erhalten. In einigen Architekturen wird der Zugriff auf falsch ausgerichtete Daten von einem Ausnahmebehandler behandelt. Vielleicht möchten Sie einen Sonderfall EXCEPTION_DATATYPE_MISALIGNMENT Und lassen Sie es an den Aufnahmehandler mit höherem Niveau weitergeben.

Ich schließe die Register, die App -Version und die Build -Nummer, den Ausnahmetyp und einen Stack -Dump in Hex ein, der mit Modulnamen und Offsets für Hex -Werte kommentiert wird, die Adressen zum Code sein könnten. Stellen Sie sicher, dass Sie die Versionsnummer und das Erstellen von Nummer/Datum Ihres EXE einfügen.

Sie können auch verwenden VirtualQuery Um Stapelwerte in "ModulenName+Offset" ziemlich leicht zu verwandeln. Und das, kombiniert mit einer .MAP -Datei, zeigt Ihnen oft genau, wo Sie abgestürzt sind.

Ich stellte fest, dass ich Beta -Tester trainieren konnte, um meinen Text ziemlich leicht zu senden, aber in den frühen Tagen war das, was ich bekam, ein Bild des Fehlerdialogfelds und eher den Text. Ich denke, das liegt daran, dass viele Benutzer nicht wissen, dass Sie mit der rechten Maustaste auf eine beliebige Bearbeitungssteuerung klicken können, um ein Menü mit "All" und "Copy" zu erhalten. Wenn ich es noch einmal tun würde, würde ich eine Schaltfläche hinzufügen, die diesen Text in die Zwischenablage kopierte, damit er leicht in eine E -Mail eingefügt werden kann.

Noch besser, wenn Sie sich die Mühe machen möchten, eine Schaltfläche "Fehlerbericht senden" zu haben, aber nur die Möglichkeit zu geben, den Text in ihre eigenen E -Mails zu bringen über "Welche Informationen teile ich mit ihnen?"

Tatsächlich wurde Boost :: Diagnostic_information speziell in einem "globalen" Catch (...) -Block verwendet, um Informationen zu Ausnahmen anzuzeigen, die es nicht hätte erreichen dürfen. Beachten Sie jedoch, dass die von Boost :: Diagnostic_information zurückgegebene Zeichenfolge nicht benutzerfreundlich ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top