从0开始C++(十):异常处理——throw、try-catch、标准异常体系与粗略捕获

发布于:2024-06-28 ⋅ 阅读:(11) ⋅ 点赞:(0)

目录

概念

抛出异常(throw)

捕获异常(try - catch)

标准异常体系

自定义异常

多重捕获

粗略捕获


概念

异常是程序在执行期间产生的问题,C++异常是指在程序运行时发生的特殊情况,比如下所示的范围越界等。

异常提供了一种转移控制权的方式。

程序一旦出现没有经过处理的异常,就会造成程序运行崩溃。

异常处理机制可以帮助开发人员在程序发生异常时进行适当的处理,以确保程序可以正常执行或提供错误信息。

C++的异常处理通过使用 try 、catch throw 关键字来实现。 try 块用于包含可能引发异常的代码,而 catch 块用于捕获并处理异常。 throw 关键字用于引发异常。

注意,在使用异常处理时,我们应该遵循以下几点:

  1. 只在真正需要时使用异常处理,不要滥用异常。
  2. 不要在循环或频繁调用的代码块中使用异常处理,以避免性能问题。
  3. 在 catch 块中应尽量提供详细的错误信息,以帮助调试和诊断问题。

抛出异常(throw)

使用 throw 关键字可以抛出异常。throw 关键字后面可以跟着一个表达式,该表达式的结果将被当作异常对象。

以下是一个示例,演示如何使用 throw 抛出异常:

double divide(double a, double b) {
    if (b == 0) {
        throw "Divide by zero exception";
    }
    
    return a / b;
}

在上述示例中,我们定义了一个 divide 函数,用于计算两个数的商。在函数内部,我们检查除数是否为零。如果除数为零,则使用 throw关键字抛出一个字符串异常对象。

捕获异常(try - catch)

在C++中,我们可以使用 try-catch块来捕获异常。try块用于包含可能引发异常的代码,而catch块用于处理捕获的异常。

以下是一个示例,演示如何使用try-catch捕获异常:

#include <iostream>

double divide(double a, double b) {
    if (b == 0) {
        throw "Divide by zero exception";
    }
    
    return a / b;
}

int main() {
    try {
        double result = divide(10, 0);

        std::cout << "Result: " << result << std::endl;
    } catch (const char* error) {
        std::cout << "Error: " << error << std::endl;
    }
    
    return 0;
}

在上述示例中,我们定义了一个divide函数,用于计算两个数的商。在函数内部,我们检查除数是否为零。如果除数为零,则使用throw关键字抛出一个字符串异常对象。

main函数中,我们将调用divide函数放在一个try块中。如果在try块中的代码引发了异常,控制流会立即跳转到匹配的catch块,并执行其中的代码。在这个示例中,我们使用catch (const char* error)来捕获字符串异常对象,并在catch块中输出错误信息。

注意,在catch块中,我们可以使用不同类型的参数来捕获不同类型的异常对象。在上述示例中,我们使用了const char*来捕获异常对象,因为我们抛出的异常是一个字符串。

如果没有匹配的catch块来处理异常,异常将继续向上层调用栈传播,直到找到一个匹配的catch块或者到达程序的入口点(main函数)。如果一直没有找到匹配的catch块,程序将终止并显示一个未处理异常的错误消息。

标准异常体系

C++标准异常体系定义了一组异常类,用于以统一的方式处理异常情况。这些异常类都派生自基类std::exception,该基类定义了一些通用的操作和成员函数,如what()函数用于返回异常的描述信息。

  class exception
  {
  public:
    exception() _GLIBCXX_USE_NOEXCEPT { }
    virtual ~exception() _GLIBCXX_USE_NOEXCEPT;

    /** Returns a C-style character string describing the general cause
     *  of the current error.  */
    virtual const char* what() const _GLIBCXX_USE_NOEXCEPT;
  };

C++标准异常体系中的异常类包括:

  1. std::bad_alloc:内存分配失败时 抛出的异常。
  2. std::bad_cast:类型转换失败时 抛出的异常。
  3. std::bad_exception:在处理异常时 抛出的异常。
  4. std::bad_typeidtypeid操作符获取类型信息失败时 抛出的异常。
  5. std::logic_error:由程序逻辑错误 引起的异常,包括std::invalid_argumentstd::domain_errorstd::length_errorstd::out_of_range等异常。
  6. std::runtime_error:在运行时发生的异常,包括std::range_errorstd::overflow_errorstd::underflow_error等异常。

自定义异常

 除了以上这些标准异常类,还可以自定义异常类,只需派生自std::exception即可,需要添加头文件 #include<stdexcept>

一个抛出自定义异常的例子:

#include <iostream>
#include <stdexcept>
using namespace std;


class MyException :public exception
{
public:
    // 覆盖what函数
    // throw():异常规格说明
    // 表示此函数不会出现任何异常的抛出
    const char* what() const throw()
    {
        return "自定义类型异常";
    }
};

void show(string a,string b)
{
    if(a == "#" || b == "#")
    {
        throw MyException();
    }
    cout << a << b << endl;
}
int main()
{
    cout << "请输入两个字符串" << endl;
    string a;
    string b;
    cin >> a >> b;
    try
    {
        show(a,b);
    }
    catch(MyException &e)
    {
        cout << "返回异常信息:" << e.what() << endl;
    }
    cout << "您输入的是:" << a << b << endl;
    return 0;
}

多重捕获

在C++中,可以使用多重异常捕获来处理不同类型的异常。多重异常捕获允许在同一个try块中捕获多个不同类型的异常,并执行相应的处理操作。

多重异常捕获的语法如下所示:

try {
    // 代码块
}
catch (ExceptionType1 ex) {
    // 处理类型为ExceptionType1的异常
}
catch (ExceptionType2 ex) {
    // 处理类型为ExceptionType2的异常
}
// 可以添加更多的catch块
catch (...) {
    // 处理其他类型的异常
}

try块中的代码可能会抛出不同类型的异常,每一个catch块都会尝试捕获指定的异常类型。当发生异常时,C++会按照catch块的顺序来匹配异常类型,如果找到匹配的catch块,则执行相应的处理操作。

请注意以下几点:

  1. 异常类型需要与catch块中指定的类型相匹配,包括派生类型(多态)。
  2. catch块的顺序很重要,应该按照从特定到一般的顺序排列。
  3. 可以添加多个catch块来处理不同类型的异常。
  4. 可以使用省略号 ...来捕获其他未被前面的catch块捕获的异常,通常在最后一个catch块中使用。

通过多重异常捕获,可以灵活地处理不同类型的异常,确保程序在遇到异常时能够进行适当的处理操作。

粗略捕获

粗略异常捕获(也称为粗糙的异常处理)是通过catch块捕获异常,除了可以直接捕获异常类型外,也可以捕获异常的基类,甚至所有异常类型。粗略异常捕获使用省略号...作为异常类型,可以捕获任何类型的异常。

以下是C++中粗略异常捕获的语法:

try {
    // 代码块
}
catch (...) {
    // 处理所有类型的异常
}

try块中的代码可能会抛出任何类型的异常,当发生异常时,粗略异常捕获的catch块会捕获并处理异常。您可以在catch块中执行适当的操作,如输出错误信息、记录日志或进行其他处理。

粗略异常捕获应该在某些情况下使用,例如当您希望在程序遇到任何类型的异常时都能进行某种处理时。然而,粗略异常捕获会损失异常的详细信息,因此在一般情况下,更推荐使用多重异常捕获来处理不同类型的异常,以便根据异常类型采取相应的处理方式。