2025-04-17【C/C++】C++的异常抛出处理规则

假设有异常

enum class Table { Test, XX };
static std::string name(Table table) {
        switch(table) {
            case Table::Test: return "TEST";
            default: throw std::invalid_argument("Unknown table");
        }
    }

当执行代码:

std::string xx = TableMeta::name(Table::XX);

会抛出异常
当异常被抛出时,如果没有在当前函数中被 catch 捕获,它会沿着调用栈向上传播,寻找合适的 catch 块来处理。

如果在整个程序中都没有找到匹配的 catch 块来处理这个异常,那么程序会调用 std::terminate 函数来终止程序的执行。在程序终止前,标准库通常会输出一些与异常相关的错误信息到标准错误流 stderr,然后就能看到自动打印错误日志。

如果我们手动写try catch捕获异常,就能接管C++的异常处理流程,可以自由打印输出,或者用其他形式停止程序,甚至不停止程序

     try
    {
        std::string xx = TableMeta::name(Table::XX);
    }
    catch(const std::exception& e)
    {
        std::cerr << e.what() << '\n';
        std::cout << "发生错误 按下任意键关闭程序\n"; 
        std::cin.get();
        return 1;
    }
  • std::exception是所有异常派生类的基类,无论throw嵌套多深,最终都能被std::exception接收
  • e.what()本身就是类型为const char*的C风格字符串
  • 不会捕获:非 std::exception 类型的异常(如 throw 42;)。
  • std::exception的派生类型

主要派生类(按功能分类)

1. 逻辑错误(std::logic_error

表示程序逻辑错误,通常应在编码时避免:

  • std::invalid_argument → 参数无效(例如函数接收到非法值)
  • std::domain_error → 数学运算定义域错误(如 sqrt(-1)
  • std::length_error → 超出容器长度限制(如 std::vector::reserve 过大)
  • std::out_of_range → 越界访问(如 std::vector::at 越界)

2. 运行时错误(std::runtime_error

表示运行时发生的、难以预料的错误:

  • std::range_error → 计算结果超出有效范围(如浮点数溢出)
  • std::overflow_error → 算术上溢(如 INT_MAX + 1
  • std::underflow_error → 算术下溢(如浮点数精度丢失)
  • std::system_error → 系统调用错误(如文件/网络操作失败)

3. 其他标准异常

  • std::bad_alloc → 内存分配失败(newmalloc 失败)
  • std::bad_castdynamic_cast 转换失败(RTTI 相关)
  • std::bad_typeidtypeid 操作失败(RTTI 相关)
  • std::bad_exception → 未预期的异常(罕见)

继承关系图示

std::exception
├── std::logic_error
│   ├── std::invalid_argument
│   ├── std::domain_error
│   ├── std::length_error
│   └── std::out_of_range
├── std::runtime_error
│   ├── std::range_error
│   ├── std::overflow_error
│   ├── std::underflow_error
│   └── std::system_error
├── std::bad_alloc
├── std::bad_cast
├── std::bad_typeid
└── std::bad_exception

使用示例

#include <stdexcept>
#include <vector>

void validate(int value) {
    if (value < 0) 
        throw std::invalid_argument("值不能为负数");
}

int main() {
    try {
        std::vector<int> v = {1, 2, 3};
        std::cout << v.at(10);  // 抛出 std::out_of_range
    } 
    catch (const std::out_of_range& e) {
        std::cerr << "越界错误: " << e.what() << std::endl;
    }
    catch (const std::exception& e) {
        std::cerr << "其他异常: " << e.what() << std::endl;
    }
}

tips

优先捕获具体异常:先捕获派生类(如 std::out_of_range),再用 std::exception 兜底。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容