Dies ist ein Beispiel dafür, was ich häufig mache, wenn ich einer Ausnahme einige Informationen hinzufügen möchte:
std::stringstream errMsg;
errMsg << "Could not load config file '" << configfile << "'";
throw std::exception(errMsg.str().c_str());
Gibt es einen schöneren Weg, es zu tun?
std∷exception
haben keinen Konstruktor mitchar*
arg.std::string
hat einen impliziten Konstruktor, der eineconst char*
...std::exception
Klassen zu sein und wird von deren Versionen vonstd::runtime_error
und verwendetstd::logic_error
. Abgesehen von denen , durch den Standard definiert, MSVS‘Version<exception>
enthält auch zwei weitere Konstrukteure, eine Aufnahme(const char * const &)
und die andere Aufnahme(const char * const &, int)
. Sie werden verwendet, um eine private Variableconst char * _Mywhat
festzulegen. Wenn_Mywhat != nullptr
, wirdwhat()
standardmäßig zurückgegeben. Code, der darauf basiert, ist wahrscheinlich nicht portabel.Antworten:
Hier ist meine Lösung:
Beispiel:
quelle
Die Standardausnahmen können konstruiert werden aus
std::string
:Beachten Sie, dass die Basisklasse
std::exception
kann nicht so konstruiert werden; Sie müssen eine der konkreten, abgeleiteten Klassen verwenden.quelle
Es gibt verschiedene Ausnahmen wie
runtime_error
,range_error
,overflow_error
,logic_error
, etc .. Sie müssen die Zeichenfolge in den Konstruktor zu übergeben, und Sie können verketten , was Sie zu Ihrer Nachricht. Das ist nur eine String-Operation.Sie können auch
boost::format
wie folgt verwenden:quelle
Die folgende Klasse könnte sehr praktisch sein:
Anwendungsbeispiel:
quelle
throw std::runtime_error(sprintf("Could not load config file '%s'", configfile.c_str()))
throw std::runtime_error("Could not load config file " + configfile);
(Konvertieren des einen oder anderen Arguments instd::string
falls erforderlich).printf
In C ++ 11 stehen tragbare Typen und Freunde unmittelbar bevor. Puffer mit fester Größe sind sowohl ein Segen als auch ein Fluch: Er schlägt in Situationen mit geringen Ressourcen nicht fehl, kann jedoch die Nachricht abschneiden. Ich halte das Abschneiden einer Fehlermeldung für eine bessere Option als das Fehlschlagen. Die Bequemlichkeit von Formatzeichenfolgen wurde auch in vielen verschiedenen Sprachen nachgewiesen. Aber Sie haben Recht, es ist weitgehend Geschmackssache.Verwenden Sie den String-Literal-Operator, wenn C ++ 14 (
operator ""s
)oder definieren Sie Ihre eigenen, wenn in C ++ 11. Zum Beispiel
Ihre Wurfanweisung sieht dann so aus
das sieht schön und sauber aus.
quelle
Ein wirklich schöner Weg wäre, eine Klasse (oder Klassen) für die Ausnahmen zu erstellen.
Etwas wie:
Der Grund dafür ist, dass Ausnahmen viel besser sind als nur das Übertragen einer Zeichenfolge. Indem Sie verschiedene Klassen für die Fehler bereitstellen, geben Sie Entwicklern die Möglichkeit, einen bestimmten Fehler entsprechend zu behandeln (und nicht nur eine Fehlermeldung anzuzeigen). Personen, die Ihre Ausnahme abfangen, können so spezifisch sein, wie sie es benötigen, wenn Sie eine Hierarchie verwenden.
a) Möglicherweise muss der genaue Grund bekannt sein
a) Ein anderer möchte keine Details wissen
Inspirationen zu diesem Thema finden Sie unter https://books.google.ru/books?id=6tjfmnKhT24C Kapitel 9
Darüber hinaus können Sie auch eine benutzerdefinierte Nachricht liefern, aber seien Sie vorsichtig - es ist nicht sicher ist , eine Nachricht mit entweder zu komponieren
std::string
oderstd::stringstream
oder irgendeine andere Art und Weise , die eine Ausnahme verursachen kann .Im Allgemeinen gibt es keinen Unterschied, ob Sie im Konstruktor der Ausnahme oder kurz vor dem Auslösen Speicher zuweisen (mit Zeichenfolgen in C ++ arbeiten).
std::bad_alloc
Ausnahme kann vor dem ausgelöst werden, den Sie wirklich möchten.Ein auf dem Stapel zugewiesener Puffer (wie in Maxim's Antwort) ist also sicherer.
Es wird sehr gut unter http://www.boost.org/community/error_handling.html erklärt
Der schönere Weg wäre also ein bestimmter Typ der Ausnahme und das Vermeiden des Komponierens der formatierten Zeichenfolge (zumindest beim Werfen).
quelle
Stieß auf ein ähnliches Problem: Das Erstellen von benutzerdefinierten Fehlermeldungen für meine benutzerdefinierten Ausnahmen führt zu hässlichem Code. Das war meine Lösung:
Dies trennt die Logik zum Erstellen der Nachrichten. Ich hatte ursprünglich darüber nachgedacht, what () zu überschreiben, aber dann müssen Sie Ihre Nachricht irgendwo erfassen. std :: runtime_error hat bereits einen internen Puffer.
quelle
Vielleicht das?
Es erstellt einen temporären ostringstream, ruft die Operatoren << nach Bedarf auf und umschließt diesen in runde Klammern und ruft die Funktion .str () für das ausgewertete Ergebnis (das ein ostringstream ist) auf, um einen temporären std :: string an den Konstruktor zu übergeben von runtime_error.
Hinweis: Der ostringstream und der String sind temporäre R-Werte und verlassen daher den Gültigkeitsbereich, nachdem diese Zeile endet. Der Konstruktor Ihres Ausnahmeobjekts MUSS die Eingabezeichenfolge entweder mit Kopier- oder (besser) Verschiebungssemantik verwenden.
Zusätzlich: Ich betrachte diesen Ansatz nicht unbedingt als "Best Practice", aber er funktioniert und kann zur Not verwendet werden. Eines der größten Probleme ist, dass diese Methode Heap-Zuweisungen erfordert und der Operator << werfen kann. Sie wollen wahrscheinlich nicht, dass das passiert; Wenn Sie jedoch in diesen Zustand geraten, müssen Sie sich wahrscheinlich mehr Sorgen machen!
quelle