如何抛出一个c++异常

我对异常处理的理解很差。如何为我自己的目的定制throw, try, catch语句)。

例如,我已经定义了一个函数如下

我希望该函数在a或b为负时抛出一个带有某些消息的异常。

在函数的定义中,我应该怎么做呢?

535744 次浏览

简单:

#include <stdexcept>


int compare( int a, int b ) {
if ( a < 0 || b < 0 ) {
throw std::invalid_argument( "received negative value" );
}
}

标准库附带了一个不错的内置异常对象集合,你可以抛出。请记住,你应该总是通过值抛出,通过引用捕获:

try {
compare( -1, 3 );
}
catch( const std::invalid_argument& e ) {
// do stuff with exception...
}

在每次try之后可以有多个catch()语句,因此如果需要,可以分别处理不同的异常类型。

你也可以重新抛出异常:

catch( const std::invalid_argument& e ) {
// do something


// let someone higher up the call stack handle it if they want
throw;
}

并且不考虑异常类型而捕获异常:

catch( ... ) { };

只需在需要的地方添加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) {
// ...
}
}

另外,查看提振。异常

你可以定义一个消息,当某个错误发生时抛出:

throw std::invalid_argument( "received negative value" );

或者你可以这样定义它:

std::runtime_error greatScott("Great Scott!");
double getEnergySync(int year) {
if (year == 1955 || year == 1885) throw greatScott;
return 1.21e9;
}

通常,你会有一个像这样的try ... catch块:

try {
// do something that causes an exception
}catch (std::exception& e){ std::cerr << "exception: " << e.what() << std::endl; }

虽然这个问题已经很老了,而且已经有人回答过了,但我只想补充一点关于如何在c++ 11中进行适当的异常处理的说明:

使用std::nested_exceptionstd::throw_with_nested

StackOverflow 在这里在这里描述了如何在代码中对异常进行回溯,而不需要调试器或繁琐的日志记录,只需编写一个适当的异常处理程序,即可重新抛出嵌套异常。

因为你可以用任何派生的异常类来做这件事,你可以在这样的回溯中添加很多信息! 你也可以看一下我的MWE在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"

加上这个答案,因为在这个时候为这个问题创建另一个答案似乎没有什么好处。

在这种情况下,你创建了自己的自定义异常,派生自std::exception,当你捕获“所有可能的”;异常类型,你应该总是以“most derived”作为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;
}

注意:

  1. 正确的顺序应该是反之亦然,即-首先你catch (const MyException& e),然后是catch (const std::exception& e)

  2. 正如你所看到的,当你运行程序时,第一个catch子句将被执行(这可能是你首先想要的)。

  3. 尽管在第一个catch子句中捕获的类型是std::exception类型,但" property "what()的版本将被调用-因为它是通过引用捕获的(至少将捕获的参数std::exception类型更改为通过值捕获-并且你将体验到“对象切片”;现象在行动)。

  4. 如果“某些代码由于XXX异常被抛出”;做重要的事情关于异常类型,这里有你的代码的不当行为。

  5. 如果捕获的对象是“正常的”,这也相关;class Base{};class Derived : public Base {}

  6. g++ 7.3.0在Ubuntu 18.04.1上产生一个警告,表明上述问题:

在函数void illustrateDerivedExceptionCatch()中: item12Linux.cpp:48:2: warning: 类型' MyException '的异常将被捕获 抓住(const MyException&e) ^ ~ ~ ~ ~ < / p >

item12Linux.cpp:43:2: warning: 通过之前的处理程序为' std::exception ' Catch (const exception&e) ^ ~ ~ ~ ~ < / p >

再一次,我会说,这个答案只是到添加到这里描述的其他答案(我认为这一点是值得一提的,但无法在评论中描述它)。