C++ 异常:抛出 std::string
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/134569/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
c++ exception : throwing std::string
提问by Palad1
I would like to throw an exception when my C++ methods encounter something weird and can't recover. Is it OK to throw a std::string
pointer?
当我的 C++ 方法遇到奇怪的事情并且无法恢复时,我想抛出一个异常。抛出一个std::string
指针可以吗?
Here's what I was looking forward to doing:
这是我期待做的事情:
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;
}
}
回答by christopher_f
Yes. std::exception
is the base exception class in the C++ standard library. You may want to avoid using strings as exception classes because they themselves can throw an exception during use. If that happens, then where will you be?
是的。std::exception
是 C++ 标准库中的基本异常类。您可能希望避免使用字符串作为异常类,因为它们本身可以在使用过程中抛出异常。如果发生这种情况,那么你会在哪里?
boost has an excellent documenton good style for exceptions and error handling. It's worth a read.
boost 有一篇关于异常和错误处理良好风格的优秀文档。值得一读。
回答by PierreBdR
A few principles:
几个原则:
you have a std::exception base class, you should have your exceptions derive from it. That way general exception handler still have some information.
Don't throw pointers but object, that way memory is handled for you.
你有一个 std::exception 基类,你应该从它派生出你的异常。这样一般异常处理程序仍然有一些信息。
不要抛出指针而是对象,这样内存就会为你处理。
Example:
例子:
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(); }
};
And then use it in your 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;
}
}
回答by PierreBdR
All these work:
所有这些工作:
#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;
}
You should prefer h to f to g. Note that in the least preferable option you need to free the memory explicitly.
你应该更喜欢 h 到 f 到 g。请注意,在最不优选的选项中,您需要明确释放内存。
回答by Daniel Spiewak
It works, but I wouldn't do it if I were you. You don't seem to be deleting that heap data when you're done, which means that you've created a memory leak. The C++ compiler takes care of ensuring that exception data is kept alive even as the stack is popped, so don't feel that you need to use the heap.
它有效,但如果我是你,我就不会这样做。完成后,您似乎没有删除该堆数据,这意味着您造成了内存泄漏。C++ 编译器负责确保即使在弹出堆栈时异常数据也保持活动状态,因此不要觉得您需要使用堆。
Incidentally, throwing a std::string
isn't the best approach to begin with. You'll have a lot more flexibility down the road if you use a simple wrapper object. It may just encapsulate a string
for now, but maybe in future you will want to include other information, like some data which caused the exception or maybe a line number (very common, that). You don't want to change all of your exception handling in every spot in your code-base, so take the high road now and don't throw raw objects.
顺便说一句,抛出 astd::string
并不是最好的开始方法。如果您使用一个简单的包装器对象,那么您将有更多的灵活性。它现在可能只是封装了 a string
,但也许将来您会想要包含其他信息,例如一些导致异常的数据或行号(非常常见)。您不想更改代码库中每个位置的所有异常处理,所以现在就走大路,不要抛出原始对象。
回答by Michael Burr
In addition to probably throwing something derived from std::exception you should throw anonymous temporaries and catch by reference:
除了可能抛出从 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;
}
}
- You should throw anonymous temporaries so the compiler deals with the object lifetime of whatever you're throwing - if you throw something new-ed off the heap, someone else needs to free the thing.
- You should catch references to prevent object slicing
- 您应该抛出匿名临时对象,以便编译器处理您抛出的任何对象的对象生命周期 - 如果您从堆中抛出一些新的东西,其他人需要释放它。
- 您应该捕获引用以防止对象切片
.
.
See Meyer's "Effective C++ - 3rd edition" for details or visit https://www.securecoding.cert.org/.../ERR02-A.+Throw+anonymous+temporaries+and+catch+by+reference
有关详细信息,请参阅 Meyer 的“Effective C++ - 3rd edition”或访问https://www.securecoding.cert.org/.../ERR02-A.+Throw+anonymous+temporaries+and+catch+by+reference
回答by Eric Leschinski
Simplest way to throw an Exception in C++:
在 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;
}
This prints:
这打印:
We caught a message: Cannot purturb at this time.
done
If you catch the thrown exception, the exception is contained and the program will ontinue. If you do not catch the exception, then the program exists and prints:
如果捕获抛出的异常,则包含异常并且程序将继续运行。如果没有捕获异常,则程序存在并打印:
This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.
This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.
回答by GPMueller
Though this question is rather old and has already been answered, I just want to add a note on how to do proper exception handling in C++11:
虽然这个问题已经很老了并且已经得到了回答,但我只想添加一个关于如何在 C++11 中进行正确异常处理的注释:
Use std::nested_exception
and std::throw_with_nested
使用std::nested_exception
和std::throw_with_nested
Using these, in my opinion, leads to cleaner exception design and makes it unnecessary to create an exception class hierarchy.
在我看来,使用这些可以使异常设计更清晰,并且无需创建异常类层次结构。
Note that this enables you to get a backtrace on your exceptionsinside your code without need for a debugger or cumbersome logging. It is described on StackOverflow hereand here, how to write a proper exception handler which will rethrow nested exceptions.
请注意,这使您无需调试器或繁琐的日志记录即可获得代码中异常的回溯。在此处和此处的StackOverflow 上描述了如何编写适当的异常处理程序,该处理程序将重新抛出嵌套异常。
Since you can do this with any derived exception class, you can add a lot of information to such a backtrace! You may also take a look at my MWE on GitHub, where a backtrace would look something like this:
由于您可以使用任何派生的异常类来执行此操作,因此您可以向此类回溯添加大量信息!您也可以在 GitHub 上查看我的MWE,其中的回溯如下所示:
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"