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块中释放它们!如果发现原始点太麻烦,请改用智能指针!

