异常处理

基本概念

异常处理用于处理程序运行时发生的错误,将“错误检测”与“错误处理”分离。

  • 抛出异常:使用 throw 表达式
  • 捕获异常:使用 trycatch
  • 传播:若当前函数未捕获,异常沿调用栈向上传递;直到 main 仍未捕获则调用 terminate() 终止程序

基本语法

#include <iostream>
using namespace std;

double divide(double a, double b) {
    if (b == 0)
        throw "除数不能为零";      // 抛出 const char* 类型的异常
    return a / b;
}

int main() {
    try {
        double result = divide(10, 0);
        cout << result << endl;
    }
    catch (const char* msg) {      // 捕获 const char* 异常
        cerr << "错误: " << msg << endl;
    }
    return 0;
}

输出:错误: 除数不能为零


throw 表达式

throw 可以抛出任何类型的对象(基本类型、指针、类对象)。通常抛出派生自 std::exception 的类对象。

throw 42;                    // 抛出 int
throw "error";               // 抛出 const char*
throw MyException();         // 抛出自定义类对象
throw;                       // 重新抛出当前捕获的异常(仅在 catch 块内使用)

重新抛出示例:

try {
    // ...
}
catch (...) {               // 捕获所有异常
    // 做一些清理工作
    throw;                  // 将原异常继续向上传递
}

trycatch

多个 catch 子句

按顺序匹配,一旦匹配成功,后续 catch 不再执行。应把更特化的类型放在前面

try {
    // code
}
catch (int e) {
    cout << "捕获整数异常: " << e << endl;
}
catch (const char* e) {
    cout << "捕获字符串异常: " << e << endl;
}
catch (...) {               // 捕获任何未被上面匹配的异常
    cout << "未知异常" << endl;
}

按引用捕获

推荐按 const 引用 捕获,避免对象拷贝及 slicing(派生类被切为基类)。

catch (const exception& e) {
    cerr << e.what() << endl;
}

函数内的 try/catch

整个函数体可以用 try 包裹:

void func() try {
    // 函数体
}
catch (const exception& e) {
    // 处理
}

这种形式常用于构造函数初始化列表中抛出异常的情况。


标准异常类(了解,不重要)

C++ 标准库提供 <stdexcept> 中的异常类层次,所有异常都继承自基类 exception(位于 <exception>)。

常用标准异常

异常类头文件说明
exception<exception>所有标准异常的基类
logic_error<stdexcept>逻辑错误,程序可预判
domain_error<stdexcept>定义域错误
invalid_argument<stdexcept>无效参数
length_error<stdexcept>长度过长
out_of_range<stdexcept>超出范围(如 vector::at()
runtime_error<stdexcept>运行时错误,难以预判
range_error<stdexcept>内部计算范围错误
overflow_error<stdexcept>算术上溢
underflow_error<stdexcept>算术下溢
bad_alloc<new>new 分配失败
bad_cast<typeinfo>dynamic_cast 失败(引用)

使用示例

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

int getCharAt(const string& s, int idx) {
    if (idx < 0 || idx >= s.size())
        throw out_of_range("索引超出范围");
    return s[idx];
}

int main() {
    try {
        getCharAt("hello", 10);
    }
    catch (const out_of_range& e) {
        cerr << "out_of_range: " << e.what() << endl;
    }
    catch (const exception& e) {   // 捕获其他标准异常
        cerr << "exception: " << e.what() << endl;
    }
    return 0;
}

what() 成员函数返回错误描述字符串。


自定义异常类(略,不重要)

继承自 std::exception(或它的派生类),并覆盖 what()

#include <exception>
#include <iostream>
#include <cstring>
using namespace std;

class MyException : public exception {
private:
    char msg[100];
public:
    MyException(const char* errorMsg) {
        strncpy(msg, errorMsg, sizeof(msg) - 1);
        msg[sizeof(msg)-1] = '\0';
    }
    const char* what() const noexcept override {
        return msg;
    }
};

// 更简洁的方式:继承 runtime_error
#include <stdexcept>
class MyRuntimeError : public runtime_error {
public:
    MyRuntimeError(const string& msg) : runtime_error(msg) {}
};

int main() {
    try {
        throw MyException("自定义错误");
    }
    catch (const MyException& e) {
        cerr << e.what() << endl;
    }
    return 0;
}

注意what() 应声明为 noexcept,且不应抛出异常。

noexcept 说明符

声明函数不会抛出异常。

可用 noexcept(expression) 根据条件决定是否 noexcept