Ich möchte eine Ausnahme auslösen, wenn meine C ++ - Methoden auf etwas Seltsames stoßen und nicht wiederhergestellt werden können. Ist es in Ordnung, einen std::string
Zeiger zu werfen ?
Darauf habe ich mich gefreut:
void Foo::Bar() {
if(!QueryPerformanceTimer(&m_baz)) {
throw new std::string("it's the end of the world!");
}
}
void Foo::Caller() {
try {
this->Bar(); // should throw
}
catch(std::string *caught) { // not quite sure the syntax is OK here...
std::cout << "Got " << caught << std::endl;
}
}
Antworten:
Ja.
std::exception
ist die Basisausnahmeklasse in der C ++ - Standardbibliothek. Möglicherweise möchten Sie die Verwendung von Zeichenfolgen als Ausnahmeklassen vermeiden, da diese während der Verwendung selbst eine Ausnahme auslösen können. Wenn das passiert, wo wirst du dann sein?boost verfügt über ein hervorragendes Dokument zu gutem Stil für Ausnahmen und Fehlerbehandlung. Es ist eine Lektüre wert.
quelle
Einige Prinzipien:
Wenn Sie eine Basisklasse std :: exception haben, sollten Ihre Ausnahmen davon abgeleitet sein. Auf diese Weise haben allgemeine Ausnahmebehandlungsroutinen noch einige Informationen.
Wirf keine Zeiger, sondern Objekte, so wird der Speicher für dich gehandhabt.
Beispiel:
struct MyException : public std::exception { std::string s; MyException(std::string ss) : s(ss) {} ~MyException() throw () {} // Updated const char* what() const throw() { return s.c_str(); } };
Und dann verwenden Sie es in Ihrem Code:
void Foo::Bar(){ if(!QueryPerformanceTimer(&m_baz)){ throw MyException("it's the end of the world!"); } } void Foo::Caller(){ try{ this->Bar();// should throw }catch(MyException& caught){ std::cout<<"Got "<<caught.what()<<std::endl; } }
quelle
All diese Arbeiten:
#include <iostream> using namespace std; //Good, because manual memory management isn't needed and this uses //less heap memory (or no heap memory) so this is safer if //used in a low memory situation void f() { throw string("foo"); } //Valid, but avoid manual memory management if there's no reason to use it void g() { throw new string("foo"); } //Best. Just a pointer to a string literal, so no allocation is needed, //saving on cleanup, and removing a chance for an allocation to fail. void h() { throw "foo"; } int main() { try { f(); } catch (string s) { cout << s << endl; } try { g(); } catch (string* s) { cout << *s << endl; delete s; } try { h(); } catch (const char* s) { cout << s << endl; } return 0; }
Sie sollten h gegenüber f gegenüber g bevorzugen. Beachten Sie, dass Sie in der am wenigsten bevorzugten Option den Speicher explizit freigeben müssen.
quelle
const char
Zeigers auf eine lokale Variable nicht ein Fehler? Ja, natürlich weiß ich, dass der Compiler den C-String in den unveränderten Abschnitt legt, der die Adresse erst ändert, wenn eine App ausgeführt wird. Aber es ist undefiniert; Was wäre, wenn dieser Code in einer Bibliothek wäre, die kurz nach dem Auslösen eines Fehlers verschwunden wäre? Übrigens habe auch ich in meinem Projekt so viele schlechte Dinge getan, ich bin nur ein Student. Aber ich hätte darüber nachdenken sollen ...Es funktioniert, aber ich würde es nicht tun, wenn ich du wäre. Sie scheinen diese Heap-Daten nicht zu löschen, wenn Sie fertig sind, was bedeutet, dass Sie einen Speicherverlust verursacht haben. Der C ++ - Compiler sorgt dafür, dass Ausnahmedaten auch dann erhalten bleiben, wenn der Stapel geöffnet wird. Sie müssen also nicht den Heap verwenden.
Übrigens ist das Werfen von a zunächst
std::string
nicht der beste Ansatz. Wenn Sie ein einfaches Wrapper-Objekt verwenden, haben Sie später viel mehr Flexibilität. Möglicherweise kapselt es nur einestring
für den Moment, aber möglicherweise möchten Sie in Zukunft andere Informationen einschließen, z. B. einige Daten, die die Ausnahme verursacht haben, oder möglicherweise eine Zeilennummer (sehr häufig). Sie möchten nicht die gesamte Ausnahmebehandlung an jeder Stelle in Ihrer Codebasis ändern. Gehen Sie also jetzt auf die Straße und werfen Sie keine rohen Objekte.quelle
Zusätzlich zum wahrscheinlichen Auslösen von etwas, das von std :: exception abgeleitet ist, sollten Sie anonyme Provisorien werfen und nach Referenz abfangen:
void Foo::Bar(){ if(!QueryPerformanceTimer(&m_baz)){ throw std::string("it's the end of the world!"); } } void Foo:Caller(){ try{ this->Bar();// should throw }catch(std::string& caught){ // not quite sure the syntax is ok here... std::cout<<"Got "<<caught<<std::endl; } }
.
Weitere Informationen finden Sie in Meyers "Effective C ++ - 3rd Edition" oder unter https://www.securecoding.cert.org/.../ERR02-A.+Throw+anonymous+temporaries+and+catch+by+reference
quelle
Einfachste Möglichkeit, eine Ausnahme in C ++ auszulösen:
#include <iostream> using namespace std; void purturb(){ throw "Cannot purturb at this time."; } int main() { try{ purturb(); } catch(const char* msg){ cout << "We caught a message: " << msg << endl; } cout << "done"; return 0; }
Dies druckt:
We caught a message: Cannot purturb at this time. done
Wenn Sie die ausgelöste Ausnahme abfangen, ist die Ausnahme enthalten und das Programm wird fortgesetzt. Wenn Sie die Ausnahme nicht abfangen, ist das Programm vorhanden und druckt:
This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.
quelle
catch (std::exception&)
wird es nicht verstehen.Obwohl diese Frage ziemlich alt ist und bereits beantwortet wurde, möchte ich nur einen Hinweis zur ordnungsgemäßen Ausnahmebehandlung in C ++ 11 hinzufügen :
Verwenden Sie
std::nested_exception
undstd::throw_with_nested
Die Verwendung dieser führt meiner Meinung nach zu einem saubereren Ausnahmedesign und macht es unnötig, eine Ausnahmeklassenhierarchie zu erstellen.
Beachten Sie, dass Sie auf diese Weise eine Rückverfolgung Ihrer Ausnahmen in Ihrem Code erhalten können, ohne dass ein Debugger oder eine umständliche Protokollierung erforderlich ist. In StackOverflow wird hier und hier beschrieben , wie Sie einen geeigneten Ausnahmebehandler schreiben, der verschachtelte Ausnahmen erneut auslöst.
Da Sie dies mit jeder abgeleiteten Ausnahmeklasse tun können, können Sie einer solchen Rückverfolgung viele Informationen hinzufügen! Sie können sich auch mein MWE auf GitHub ansehen, wo ein Backtrace ungefähr so aussehen würde:
Library API: Exception caught in function 'api_function' Backtrace: ~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed ~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
quelle