<stdexcept> 是 C++ 标准库中专门用于提供标准异常类的头文件。这些异常类继承自 std::exception,为常见错误情况提供了具体的异常类型,使得程序可以抛出和捕获更具描述性的异常,从而提高代码的可读性和健壮性。


目录

  1. 简介
  2. 常见的标准异常类
  3. 使用 <stdexcept> 抛出异常
  4. 捕获和处理标准异常
  5. 自定义异常与 <stdexcept> 的关系
  6. 常见注意事项
  7. 结论

1. 简介

<stdexcept> 定义了许多标准异常类,用于描述程序中可能发生的错误。相比直接使用 std::exception,这些类能够更具体地表达错误类型,从而让异常处理更具语义。只需包含头文件:

#include <stdexcept>


2. 常见的标准异常类

标准异常类大致分为两类:逻辑错误(程序设计上的错误)和运行时错误(运行过程中可能出现的问题)。

2.1 逻辑错误类

逻辑错误类主要用于指示程序设计中违反预期条件的错误,这些错误通常可以在编译前或运行前检查出来。常见的逻辑错误类包括:

  • std::logic_error:所有逻辑错误的基类。
    • std::invalid_argument:无效参数错误。例如,当传入函数的参数不符合要求时。
    • std::domain_error:参数超出函数定义域时抛出。
    • std::length_error:长度错误,如试图创建超出容器限制的对象。
    • std::out_of_range:当索引超出范围时抛出异常。

示例:

#include <iostream>
#include <stdexcept>

void validateAge(int age) {
    if (age < 0 || age > 150) {
        throw std::out_of_range("年龄超出合理范围");
    }
}

int main() {
    try {
        validateAge(200);
    } catch (const std::exception& ex) {
        std::cerr << "逻辑错误捕获: " << ex.what() << std::endl;
    }
    return 0;
}

2.2 运行时错误类

运行时错误类用于指示在程序运行过程中出现的问题,这类错误通常不能通过编译期检查发现。常见的运行时错误类包括:

  • std::runtime_error:所有运行时错误的基类。
    • std::range_error:超出范围错误,通常用于数学计算中。
    • std::overflow_error:上溢错误。
    • std::underflow_error:下溢错误。

示例:

#include <iostream>
#include <stdexcept>

double divide(double a, double b) {
    if (b == 0) {
        throw std::runtime_error("除数不能为零");
    }
    return a / b;
}

int main() {
    try {
        std::cout << "结果: " << divide(10, 0) << std::endl;
    } catch (const std::exception& ex) {
        std::cerr << "运行时错误捕获: " << ex.what() << std::endl;
    }
    return 0;
}


3. 使用 <stdexcept> 抛出异常

在遇到不符合预期的情况时,使用 <stdexcept> 中的异常类可以让异常信息更具体,便于定位问题。例如:

#include <stdexcept>
#include <string>

void setName(const std::string& name) {
    if (name.empty()) {
        throw std::invalid_argument("名称不能为空");
    }
    // 继续设置名称的操作……
}


4. 捕获和处理标准异常

在捕获异常时,推荐使用基类引用捕获(如 const std::exception&),这样可以捕获所有标准异常,且避免对象切片问题:

#include <iostream>
#include <stdexcept>

int main() {
    try {
        // 可能抛出 std::invalid_argument 或其他 std::logic_error 派生类的代码
        setName("");
    } catch (const std::exception& ex) {
        std::cerr << "异常: " << ex.what() << std::endl;
    }
    return 0;
}


5. 自定义异常与 <stdexcept> 的关系

当标准异常类不能满足具体需求时,你可以继承自 std::logic_errorstd::runtime_error 来定义自定义异常。这样可以利用标准异常的基本接口(如 what())和继承体系,同时加入自定义的错误信息。

示例:

#include <iostream>
#include <stdexcept>
#include <string>

class MyCustomException : public std::runtime_error {
public:
    explicit MyCustomException(const std::string& msg)
        : std::runtime_error("MyCustomException: " + msg) { }
};

void process(int value) {
    if (value < 0) {
        throw MyCustomException("负值不允许");
    }
    // 其他处理……
}

int main() {
    try {
        process(-1);
    } catch (const std::exception& ex) {
        std::cerr << "捕获自定义异常: " << ex.what() << std::endl;
    }
    return 0;
}


6. 常见注意事项

  • 异常安全性:在抛出异常前,确保已经正确释放了资源(推荐使用 RAII 技术)。
  • 信息明确:选择合适的异常类型以便清楚表达错误的性质。
  • 层次结构:利用标准异常类的继承结构,有助于对不同错误进行细粒度处理。
  • 异常捕获顺序:当捕获多个异常时,先捕获派生类,再捕获基类,避免被基类捕获后遗漏处理更具体的错误。

7. 结论

<stdexcept> 为 C++ 程序提供了一套标准化的异常类,用于描述逻辑错误和运行时错误。通过合理使用这些异常类,可以使程序在出错时提供清晰、有意义的错误信息,并实现统一的错误处理策略。掌握 <stdexcept> 的使用对于编写健壮、易于维护的 C++ 应用程序至关重要。

推荐阅读: