简介

  • C++ 标准库

c++ 标准库

<exception> 标准库提供了异常处理相关的功能,包含了一些用于异常处理的类和函数。在 C++ 中,异常处理允许程序在运行时检测到错误,并且在适当的地方进行处理,而不是导致程序异常终止。

一些 <exception> 标准库中的重要组件包括:

  1. std::exception 类: 是所有标准异常类的基类。它定义了一些公共成员函数,如 what(),用于返回异常的描述信息。

  2. 标准异常类: 包括 std::bad_allocstd::bad_caststd::bad_exceptionstd::bad_typeidstd::logic_errorstd::runtime_error 等。这些类继承自 std::exception,用于表示不同类型的异常情况。

  3. 异常处理关键字: trycatchthrowtry 用于包裹可能引发异常的代码块,catch 用于捕获并处理异常,throw 用于抛出异常。

  4. std::nested_exception 这是一个模板类,它允许异常在一个异常处理器中重新抛出。

通过使用 <exception> 标准库,程序员可以更加精细地控制代码中可能出现的异常,并且可以根据情况进行处理或传递异常信息,从而提高程序的健壮性和可靠性。

c++ 标准库 详解

<exception> 标准库提供了在 C++ 中处理异常的相关功能。以下是该标准库中的一些重要组件和使用方法的详细解释:

  1. std::exception 类: 是所有标准异常类的基类。它包含了一个虚拟成员函数 what(),允许派生类提供描述异常的字符串。程序员通常通过继承 std::exception 来创建自定义异常类,并重写 what() 函数以提供特定异常的描述信息。

  2. 标准异常类: std::exception 的派生类包括:
    • std::bad_alloc:用于表示动态分配内存失败的情况。
    • std::bad_cast:用于表示类型转换失败的情况。
    • std::bad_exception:用于表示异常规范(exception specifications)未匹配的情况。
    • std::bad_typeid:用于表示 typeid 运算符失败的情况。
    • std::logic_error:用于表示在程序逻辑上可被预见的异常。
    • std::runtime_error:用于表示在运行时可能发生的异常。
  3. 异常处理关键字:
    • try:用于将可能引发异常的代码块包裹起来。
    • catch:用于捕获和处理 try 块中抛出的异常。
    • throw:用于手动抛出异常对象。
  4. std::nested_exception 这个模板类允许异常在一个异常处理器中重新抛出。它允许在捕获异常后保留异常信息,然后在另一个上下文中重新抛出异常。

异常处理是一种用于控制程序在遇到错误时如何处理的机制。通过 <exception> 标准库,程序员可以使用异常来跳出错误的代码块并在适当的地方进行处理,而不是让程序非正常终止。这有助于提高程序的可靠性和健壮性。

c++ 标准库 常用函数

<exception> 标准库并未提供太多直接调用的函数,但它定义了一些关键的类和机制来处理异常。以下是一些常用的函数和类:

  1. std::exception 是所有标准异常类的基类,它包含了一个虚拟成员函数 what(),用于返回描述异常的字符串。常用于自定义异常类的基类。

  2. 标准异常类: 派生自 std::exception,如 std::bad_allocstd::bad_caststd::logic_errorstd::runtime_error 等。每个异常类都可以通过构造函数接受字符串来描述异常。

  3. 异常处理关键字: trycatchthrow
    • try 用于包裹可能引发异常的代码块。
    • catch 用于捕获并处理 try 块中抛出的异常,其语法为 catch (const SomeExceptionType& ex)
    • throw 用于手动抛出异常对象,可以是标准异常类的实例或者用户自定义的异常类的实例。
  4. std::nested_exception 模板类允许异常在一个异常处理器中重新抛出,以便在另一个上下文中处理异常。

虽然 <exception> 标准库并不包含太多的直接函数,但它提供了一套机制和类,可以帮助程序员在程序执行过程中检测和处理异常,从而提高程序的可靠性和健壮性。

std::exception

std::exception 是 C++ 标准库 <exception> 中的一个类,是所有标准异常类的基类。它被设计为一个抽象基类,用于派生出各种不同类型的异常类,以表示不同的异常情况。

std::exception 包含了一个虚拟成员函数 what(),允许派生类提供描述异常的字符串。派生类应该覆盖 what() 函数,并返回一个 C 风格的字符串,描述了异常的信息。

例如,下面是一个简单的例子展示了如何使用 std::exception 的派生类,并重写 what() 函数来提供异常信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <exception>

class MyException : public std::exception {
public:
    const char* what() const noexcept override {
        return "This is a custom exception.";
    }
};

int main() {
    try {
        throw MyException();
    } catch (const std::exception& e) {
        std::cout << "Caught exception: " << e.what() << std::endl;
    }

    return 0;
}

在这个例子中,MyException 是一个自定义异常类,它继承自 std::exception。它重写了 what() 函数,返回一个描述异常信息的字符串。在 main() 函数中,throw MyException() 语句抛出一个 MyException 类的实例,然后在 catch 块中捕获并打印异常信息。

std::bad_alloc

std::bad_alloc 是 C++ 标准库 <exception> 中的一个异常类,它是 std::exception 的一个派生类。std::bad_alloc 类通常用于表示动态内存分配失败的情况,比如使用 new 操作符申请内存时,如果内存不足或分配失败,就会抛出这个异常。

这个异常通常在需要动态分配内存(比如使用 newmalloc 或其他动态内存分配方式)的情况下使用。如果动态内存分配失败,比如尝试分配比系统可用内存还多的内存时,就会抛出 std::bad_alloc 异常。

以下是一个简单的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <new>

int main() {
    try {
        int* myArray = new int[10000000000000000]; // 尝试分配一个非常大的数组
        delete[] myArray;
    } catch (const std::bad_alloc& e) {
        std::cout << "Caught bad_alloc exception: " << e.what() << std::endl;
    }

    return 0;
}

在这个例子中,new int[10000000000000000] 尝试分配一个非常大的数组,可能超出系统可用内存的范围,因此会抛出 std::bad_alloc 异常。catch 块捕获这个异常,并打印出异常信息。

std::bad_cast

std::bad_cast 是 C++ 标准库 <exception> 中的一个异常类,它是 std::exception 的一个派生类。std::bad_cast 类通常用于表示在类型转换失败的情况下抛出的异常。

这个异常通常与 C++ 中的类型转换运算符 dynamic_cast 相关。当使用 dynamic_cast 进行转换时,如果无法将一个指针或引用转换为所需的目标类型,则会抛出 std::bad_cast 异常。

以下是一个简单的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <typeinfo>

class Base {
public:
    virtual ~Base() {}
};

class Derived : public Base {};

int main() {
    Base* basePtr = new Derived();
    Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);

    if (derivedPtr) {
        std::cout << "Successful dynamic_cast." << std::endl;
    } else {
        try {
            if(typeid(*basePtr) == typeid(Derived)) {
                throw std::bad_cast();
            }
        } catch(const std::bad_cast& e) {
            std::cout << "Caught bad_cast exception: " << e.what() << std::endl;
        }
    }

    delete basePtr;
    return 0;
}

在这个例子中,BaseDerived 是类的继承关系。在 main() 函数中,使用 dynamic_cast 尝试将 Base 指针 basePtr 转换为 Derived 类型的指针 derivedPtr。如果转换失败,dynamic_cast 返回 nullptr。在这种情况下,通过 typeid 运算符检查类型,如果类型不匹配,则手动抛出 std::bad_cast 异常。catch 块捕获这个异常,并打印出异常信息。

std::bad_exception

std::bad_exception 是 C++ 标准库 <exception> 中的一个异常类,它是 std::exception 的一个派生类。std::bad_exception 类通常用于表示异常规范(exception specifications)未匹配的情况。

在 C++ 中,异常规范(exception specifications)被用来指定一个函数可以抛出的异常类型。如果一个函数声明了它可以抛出某种异常类型,但在实际执行中抛出了不属于这个类型的异常,那么就会抛出 std::bad_exception 异常。

需要注意的是,异常规范在 C++ 中并不是强制性的,而且在现代 C++ 中,使用异常规范的做法已经不再推荐,因为它们在实际应用中存在一些问题,例如可能导致程序终止。

以下是一个简单的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <exception>

void myFunction() noexcept(false) {
    throw 10; // 抛出一个 int 类型的异常
}

int main() {
    try {
        myFunction();
    } catch (const std::bad_exception& e) {
        std::cout << "Caught bad_exception: " << e.what() << std::endl;
    }

    return 0;
}

在这个例子中,myFunction() 声明了它可以抛出异常(使用 noexcept(false)),但实际上抛出了一个 int 类型的异常。由于 std::bad_exception 指示了异常规范不匹配的情况,所以在 catch 块中捕获了 std::bad_exception 并打印出异常信息。

std::bad_typeid

std::bad_typeid 是 C++ 标准库 <exception> 中的一个异常类,它是 std::exception 的一个派生类。std::bad_typeid 类通常用于表示 typeid 运算符失败的情况。

在 C++ 中,typeid 运算符可以用来获取对象的类型信息。如果 typeid 运算符无法识别对象的类型,比如对象为空指针或者对象类型是不可识别的,则会抛出 std::bad_typeid 异常。

以下是一个简单的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <exception>
#include <typeinfo>

int main() {
    try {
        const std::type_info& info = typeid(nullptr); // typeid 对空指针的运算
        std::cout << "Type info: " << info.name() << std::endl;
    } catch (const std::bad_typeid& e) {
        std::cout << "Caught bad_typeid: " << e.what() << std::endl;
    }

    return 0;
}

在这个例子中,typeid(nullptr) 尝试获取空指针的类型信息,由于空指针不引用任何实际对象,因此 typeid 运算符无法获取其类型信息,导致抛出 std::bad_typeid 异常。catch 块捕获这个异常,并打印出异常信息。

std::logic_error

std::logic_error 是 C++ 标准库 <stdexcept> 头文件中的一个异常类,它是 std::exception 的一个派生类。std::logic_error 类通常用于表示在程序逻辑上可被预见的异常情况。

std::logic_error 类及其派生类用于表示在程序执行期间由于程序逻辑错误导致的异常,这些错误是可以在代码设计阶段预见到的。例如,当函数接收到不合理的参数时,可能会抛出 std::logic_error 异常。

以下是一个简单的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <stdexcept>

void divide(int x, int y) {
    if (y == 0) {
        throw std::logic_error("Division by zero is not allowed.");
    }
    std::cout << "Result of division: " << x / y << std::endl;
}

int main() {
    try {
        divide(10, 0); // 尝试对 10 进行除以 0 的操作
    } catch (const std::logic_error& e) {
        std::cout << "Caught logic_error: " << e.what() << std::endl;
    }

    return 0;
}

在这个例子中,divide() 函数用于执行除法操作,但在除数为 0 的情况下会抛出 std::logic_error 异常。在 main() 函数中,divide(10, 0) 尝试对 10 进行除以 0 的操作,触发了异常,并在 catch 块中捕获并打印出异常信息。

std::runtime_error

std::runtime_error 是 C++ 标准库 <stdexcept> 头文件中的一个异常类,它是 std::exception 的一个派生类。std::runtime_error 类通常用于表示在程序运行期间可能发生的异常情况。

std::runtime_error 类及其派生类用于表示在程序运行期间由于不可预测的情况导致的异常,例如文件打开失败、内存不足等。与 std::logic_error 不同,std::runtime_error 表示的异常是在运行时才能被检测到的,而不是在程序设计阶段就可以预见到的。

以下是一个简单的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <stdexcept>

void processFile(const std::string& filename) {
    // 假设在打开文件时可能发生异常
    // 这里使用 std::ifstream 模拟文件操作
    std::ifstream file(filename);
    if (!file.is_open()) {
        throw std::runtime_error("Failed to open the file.");
    }
    // 其他文件操作...
}

int main() {
    try {
        processFile("nonexistent_file.txt"); // 尝试处理一个不存在的文件
    } catch (const std::runtime_error& e) {
        std::cout << "Caught runtime_error: " << e.what() << std::endl;
    }

    return 0;
}

在这个例子中,processFile() 函数尝试打开一个文件。如果文件打开失败,就会抛出 std::runtime_error 异常。在 main() 函数中,processFile("nonexistent_file.txt") 尝试处理一个不存在的文件,触发了异常,并在 catch 块中捕获并打印出异常信息。