C++中的异常处理
在本文中,我们将介绍在C++中执行异常处理。
异常处理是一个重要的主题,尤其是在面向对象编程的情况下。
C++与Java类似,因为它可以引发和捕获异常。
我们在代码的单独部分中说明了处理异常的方法,因为它们使事情变得模块化,并使程序员更轻松。
如果检测到任何其他错误,则仅必须修改异常处理代码。
我们必须将任何引发异常的代码封装在try
块下。
因此,异常处理的三个主要部分是:
尝试块
使用可选对象以及
throw
关键字引发异常。一个catch块,用于处理异常。
该块通常紧接在" try"块之后。
引发适当的异常后,程序将立即跳至本节。
该计划的总体结构为:
try { ... throw exception; } catch(object) { ... }
让我们在以下部分中对此进行更详细的研究。
在C++中引发异常
用C++术语来说,我们将引发异常称为抛出异常。
这是通过throw
关键字完成的。
这可以采用任何对象(或者原始类型)并将其传递到异常处理代码中。
抛出对象的语法是:
//Must enclose the code in a try block try { int x = 0; call_function(x); if (x < 0) { //Throw the object, if something unwanted happened throw x; } }
现在,由于没有catch
块,程序显然还没有完成。
现在就写吧!
捕捉异常
我们提到程序会从" try"块跳转到合适的" catch"块(如果有)。
catch块具有以下结构:
catch(int x) { std::cout << "Exception thrown. Object " << x << " caught.\n"; }
每当我们的function_call(x)使x变为负数时,它将抛出异常,并显示一条消息。
现在让我们看一下完整的程序。
#include <iostream> void function_call(int& x) { //Do some work, and modify the value of x, so we're passing by reference if (x == 0) { //Set it to some negative value. We'll use this to throw an exception x = -10; //Throw an exception, and pass the object x throw x; } else { x = 100; } } int main() { int x = 0; try { function_call(x); std::cout << "If this line executes, then x != 0\n"; } catch(int x) { std::cout << "Exception thrown. Object " << x << " caught.\n"; } return 0; }
由于最初将x设置为0,我们将抛出一个异常,并打印修改后的x值(设置为-10),表明它已经执行了catch块。
另外,请注意,由于程序直接跳转到" catch",因此" function_call(x)"语句正下方的行永远不会执行。
输出
Exception thrown. Object -10 caught.
捕获所有类型的异常
如果您希望代码处理所有任意种类的异常该怎么办? C++引入了一项功能,该功能允许您使用特殊的匹配对象(...)来执行此操作。
为了捕获各种异常,我们可以编写catch(...)
来捕获我们抛出的每个对象。
当我们无法与其他任何异常匹配时,这称为默认异常,它是后备选项。
为了说明这一点,这是一个示例。
#include <iostream> #include <string> void function_call(int& x) { //Do some work, and modify the value of x, so we're passing by reference if (x == 0) { //Throw an exception, and pass on the object x throw x; } else if (x < 0) { //If x is negative, throw a random string throw std::string("Default String"); } else { x = 100; } } int main() { for (int i=0; i>=-3; i--) { try { function_call(i); std::cout << "If this line executes, then x != 0\n"; } catch(int x) { std::cout << "Exception thrown. Currently, x = " << x << " caught.\n"; } catch(...) { std::cout << "Default exception. Currently, i = " << i << " caught.\n"; } } return 0; }
输出
Exception thrown. Currently, x = 0 caught. Default exception. Currently, i = -1 caught. Default exception. Currently, i = -2 caught. Default exception. Currently, i = -3 caught.
如您所见,最初,当i = 0时,它会转到第一个catch块,因为我们返回一个整数。
但是,此后,由于我们返回字符串" Default String",因此它与第一个块不匹配,并且转到了默认块。
不幸的是,C++没有提供在默认情况下传递对象的方法,因此我们无法获得"默认字符串"字符串。
这表明我们只能将其用于为代码添加功能,以解决未知错误。
传递指针和对异常的引用
由于我们正在使用C++,因此这也是可能的!
一般规则是处理异常处理代码中与指针相关的所有释放。
try { call_function(base_ptr); } //Catch the Custom Exception Pointer using our Exception Class catch(MyException* ex_obj) { delete ex_obj; } //Catch the reference to an Exception Class object catch(MyException& ex_obj) { //Do stuff ... }
让我们考虑下面的异常处理程序类" MyException"。
#include <iostream> #include <string> class MyException { public: int err; //Error Code std::string err_msg; //String containing Error Message MyException(int val = 0) { //Base Constructor err = val; switch(val) { case(-1): err_msg = "Case -1"; break; case(-2): err_msg = "Case -2"; break; case(-3): err_msg = "Case -3"; break; default: err_msg = "##代码##"; //No error message for other cases } } ~MyException() { std::cout << "Destructor for Exception Class called\n"; } }; void function_call(int& x) { //Do some work, and modify the value of x, so we're passing by reference if (x <= 0) { //Throw an exception, and pass on the object x MyException* ex = new MyException(x); throw ex; //Throw the exception pointer } else { x = 100; } } int main() { for (int i=0; i>=-3; i--) { try { function_call(i); std::cout << "If this line executes, then x != 0\n"; } catch(MyException* ex) { std::cout << "Exception thrown. Error Message: " << ex->err_msg << "\n"; //Remember to free the pointer to the Exception!!! delete ex; } catch(...) { std::cout << "Default exception. Currently, i = " << i << " caught.\n"; } } return 0; }
我们不是直接传递整数,而是构造异常类,然后将指针传递给对象,该对象具有相关的错误代码和错误消息。
其中您可以看到使用Exception Class处理程序的强大功能!
我们不仅可以在构造函数中向其添加调试消息,而且在实际传递该消息时,我们仅移动了仅8个字节的指针!这是Java之类的其他语言无法轻易完成的。
确实,这就是我们的期望!仅针对值-1,-2和-3,我们指示构造函数设置错误消息。
对于其他值,它只是一个" NULL"字符串。
C++中异常处理的其他要点
当使用
try
和catch
块时,没有隐式类型转换发生。
因此,当将" char"传递给异常处理程序时,不会将其转换为" int"。如果使用try块,则始终使用catch块。
否则,如果引发异常,则将导致程序异常终止。模块化您的代码,以便您的核心程序逻辑与错误处理逻辑不同。
对于异常,请尝试使用相关的异常处理程序类和多态性来处理错误。如果您使用原始指针,请务必记住在您的
catch
块中释放它们!如果发现原始点太麻烦,请改用智能指针!