如何抛出 C++ 异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8480640/
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
How to throw a C++ exception
提问by Terry Li
I have a very poor understanding of exception handling(i.e., how to customize throw, try, catch statements for my own purposes).
我对异常处理的理解很差(即,如何为自己的目的自定义 throw、try、catch 语句)。
For example, I have defined a function as follows: int compare(int a, int b){...}
例如,我定义了一个函数如下: int compare(int a, int b){...}
I'd like the function to throw an exception with some message when either a or b is negative.
我希望该函数在 a 或 b 为负时抛出带有某些消息的异常。
How should I approach this in the definition of the function?
我应该如何在函数的定义中解决这个问题?
回答by nsanders
Simple:
简单的:
#include <stdexcept>
int compare( int a, int b ) {
if ( a < 0 || b < 0 ) {
throw std::invalid_argument( "received negative value" );
}
}
The Standard Library comes with a nice collection of built-in exception objectsyou can throw. Keep in mind that you should always throw by value and catch by reference:
标准库附带了一个很好的内置异常对象集合,您可以抛出这些异常对象。请记住,您应该始终按值抛出并按引用捕获:
try {
compare( -1, 3 );
}
catch( const std::invalid_argument& e ) {
// do stuff with exception...
}
You can have multiple catch() statements after each try, so you can handle different exception types separately if you want.
您可以在每次尝试后使用多个 catch() 语句,因此您可以根据需要分别处理不同的异常类型。
You can also re-throw exceptions:
您还可以重新抛出异常:
catch( const std::invalid_argument& e ) {
// do something
// let someone higher up the call stack handle it if they want
throw;
}
And to catch exceptions regardless of type:
无论类型如何,都可以捕获异常:
catch( ... ) { };
回答by Cat Plus Plus
Just add throw
where needed, and try
block to the caller that handles the error. By convention you should only throw things that derive from std::exception
, so include <stdexcept>
first.
只需throw
在需要的地方添加,并try
阻止处理错误的调用者。按照惯例,你应该只抛出从 派生的东西std::exception
,所以<stdexcept>
首先包括。
int compare(int a, int b) {
if (a < 0 || b < 0) {
throw std::invalid_argument("a or b negative");
}
}
void foo() {
try {
compare(-1, 0);
} catch (const std::invalid_argument& e) {
// ...
}
}
Also, look into Boost.Exception.
另外,看看Boost.Exception。
回答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
It is described on StackOverflow hereand here, how you can get a backtrace on your exceptionsinside your code without need for a debugger or cumbersome logging, by simply writing 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"
回答by serup
You could define a message to throw when a certain error occurs:
您可以定义在发生特定错误时抛出的消息:
throw std::invalid_argument( "received negative value" );
or you could define it like this:
或者你可以这样定义它:
std::runtime_error greatScott("Great Scott!");
double getEnergySync(int year) {
if (year == 1955 || year == 1885) throw greatScott;
return 1.21e9;
}
Typically, you would have a try ... catch
block like this:
通常,你会有一个try ... catch
像这样的块:
try {
// do something that causes an exception
}catch (std::exception& e){ std::cerr << "exception: " << e.what() << std::endl; }
回答by Guy Avraham
Wanted to ADDto the other answers described here an additional note, in the case of custom exceptions.
在自定义异常的情况下,想要添加到此处描述的其他答案的附加说明中。
In the case where you create your own custom exception, that derives from std::exception
, when you catch "all possible" exceptions types, you should always start the catch
clauses with the "most derived" exception type that may be caught. See the example (of what NOTto do):
在您创建自己的自定义异常的情况下,该异常派生自std::exception
,当您捕获“所有可能的”异常类型时,您应该始终catch
以可能捕获的“派生最多”的异常类型开始子句。见(什么样的例子不这样做):
#include <iostream>
#include <string>
using namespace std;
class MyException : public exception
{
public:
MyException(const string& msg) : m_msg(msg)
{
cout << "MyException::MyException - set m_msg to:" << m_msg << endl;
}
~MyException()
{
cout << "MyException::~MyException" << endl;
}
virtual const char* what() const throw ()
{
cout << "MyException - what" << endl;
return m_msg.c_str();
}
const string m_msg;
};
void throwDerivedException()
{
cout << "throwDerivedException - thrown a derived exception" << endl;
string execptionMessage("MyException thrown");
throw (MyException(execptionMessage));
}
void illustrateDerivedExceptionCatch()
{
cout << "illustrateDerivedExceptionsCatch - start" << endl;
try
{
throwDerivedException();
}
catch (const exception& e)
{
cout << "illustrateDerivedExceptionsCatch - caught an std::exception, e.what:" << e.what() << endl;
// some additional code due to the fact that std::exception was thrown...
}
catch(const MyException& e)
{
cout << "illustrateDerivedExceptionsCatch - caught an MyException, e.what::" << e.what() << endl;
// some additional code due to the fact that MyException was thrown...
}
cout << "illustrateDerivedExceptionsCatch - end" << endl;
}
int main(int argc, char** argv)
{
cout << "main - start" << endl;
illustrateDerivedExceptionCatch();
cout << "main - end" << endl;
return 0;
}
NOTE:
笔记:
0) The proper order should be vice-versa, i.e.- first you catch (const MyException& e)
which is followed by catch (const std::exception& e)
.
0) 正确的顺序应该是反之亦然,即 - 首先是 you catch (const MyException& e)
,然后是catch (const std::exception& e)
。
1) As you can see, when you run the program as is, the first catch clause will be executed (which is probably what you did NOTwanted in the first place).
1) 如您所见,当您按原样运行程序时,将执行第一个 catch 子句(这可能是您一开始并不想要的)。
2) Even though the type caught in the first catch clause is of type std::exception
, the "proper" version of what()
will be called - cause it is caught by reference (change at least the caught argument std::exception
type to be by value - and you will experience the "object slicing" phenomena in action).
2)即使在第一个 catch 子句中捕获的类型是 type std::exception
,what()
也会调用“正确”版本的- 因为它是通过引用捕获的(至少将捕获的参数std::exception
类型更改为按值 - 您将体验“对象切片”现象在起作用)。
3) In case that the "some code due to the fact that XXX exception was thrown..." does important stuff WITH RESPECT to the exception type, there is misbehavior of your code here.
3) 如果“由于抛出 XXX 异常这一事实而产生的某些代码......”对异常类型做了重要的事情,那么这里的代码存在不当行为。
4) This is also relevant if the caught objects were "normal" object like: class Base{};
and class Derived : public Base {}
...
4)如果捕获的对象是“正常”对象,例如:class Base{};
和class Derived : public Base {}
...
5) g++ 7.3.0
on Ubuntu 18.04.1 produces a warning that indicates the mentioned issue:
5)g++ 7.3.0
在 Ubuntu 18.04.1 上产生一个警告,指出上述问题:
In function ‘void illustrateDerivedExceptionCatch()': item12Linux.cpp:48:2: warning: exception of type ‘MyException'will be caught catch(const MyException& e) ^~~~~
item12Linux.cpp:43:2: warning: by earlier handler for ‘std::exception'catch (const exception& e) ^~~~~
在函数 'voidIllustrationDerivedExceptionCatch()': item12Linux.cpp:48:2: 警告:'MyException' 类型的异常将被捕获 catch(const MyException& e) ^~~~~
item12Linux.cpp:43:2: 警告: 由较早的处理程序用于 'std::exception'catch (const exception& e) ^~~~~
Again, I will say, that this answer is only to ADDto the other answers described here (I thought this point is worth mention, yet could not depict it within a comment).
再次,我会说,这个答案只是添加到这里描述的其他答案(我认为这一点值得一提,但无法在评论中描述)。