当我的C ++方法遇到奇怪且无法恢复的东西时,我想抛出异常。抛出std::string
指针是否可以?
以下是我期待的事情:
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;
}
}
答案 0 :(得分:96)
是。 std::exception
是C ++标准库中的基本异常类。您可能希望避免将字符串用作异常类,因为它们本身可以在使用期间抛出异常。如果发生这种情况,那你将在哪里?
boost具有出色的document样式。值得一读。
答案 1 :(得分:58)
一些原则:
你有一个std :: exception基类,你应该从它派生例外。这样一般的异常处理程序仍然有一些信息。
不要抛出指针而是对象,这样就可以为你处理内存。
示例:
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(); }
};
然后在您的代码中使用它:
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;
}
}
答案 2 :(得分:21)
所有这些工作:
#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;
}
你应该更喜欢h到f到g。请注意,在最不优选的选项中,您需要明确释放内存。
答案 3 :(得分:7)
它有效,但如果我是你,我不会这样做。完成后,您似乎没有删除该堆数据,这意味着您已经创建了内存泄漏。 C ++编译器负责确保即使在弹出堆栈时异常数据也保持活动状态,因此不要觉得您需要使用堆。
顺便说一句,抛出std::string
并不是最好的方法。如果你使用一个简单的包装器对象,你将会有更多的灵活性。它现在可能只封装一个string
,但是将来你可能希望包含其他信息,例如导致异常的一些数据或者行号(非常常见)。您不希望在代码库中的每个位置更改所有异常处理,因此请立即采取行动,不要丢弃原始对象。
答案 4 :(得分:7)
除了可能抛出从std :: exception派生的东西之外,你应该抛出匿名临时值并通过引用捕获:
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;
}
}
有关详细信息,请参阅Meyer的“Effective C ++ - 3rd edition”或访问https://www.securecoding.cert.org/.../ERR02-A.+Throw+anonymous+temporaries+and+catch+by+reference
答案 5 :(得分:4)
在C ++中抛出异常的最简单方法:
#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;
}
打印:
We caught a message: Cannot purturb at this time.
done
如果捕获抛出的异常,则包含异常并且程序将继续。如果您没有捕获异常,则程序存在并打印:
This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.
答案 6 :(得分:1)
虽然这个问题相当陈旧且已经得到解答,但我只是想补充说明如何在C ++ 11中进行正确的异常处理 :
std::nested_exception
和std::throw_with_nested
在我看来,使用这些可以实现更清晰的异常设计,并且不必创建异常类层次结构。
请注意,这使您能够在代码中获得异常的回溯,而无需调试程序或繁琐的日志记录。 StackOverflow here和here中描述了如何编写适当的异常处理程序,它将重新抛出嵌套异常。
由于您可以对任何派生的异常类执行此操作,因此可以向此类回溯添加大量信息! 您还可以查看我的MWE on GitHub,其中回溯看起来像这样:
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"