C++ 异常处理
一、异常处理到底是啥?
简单说,异常处理 就是 C++ 里专门用来 “捕获程序运行时意外错误” 的机制。比如程序要打开一个不存在的文件、数组下标越界、内存分配失败这些 “突发情况”,如果不处理,程序会直接崩溃;用异常处理,就能优雅地接住这些错误,让程序继续运行或友好退出。
可以类比成:你点外卖(程序执行),正常情况能收到餐(代码正常跑),但偶尔会遇到 “商家没货”“骑手超时”(异常)—— 异常处理就是让你不用干等着崩溃,而是能选择 “换一家店”“取消订单”(处理异常)。
二、核心语法(怎么用)
C++ 异常处理有 3 个核心关键字:try、throw、catch,三者配合使用,先看完整示例代码:
cpp
运行
#include <iostream> #include <stdexcept> // 包含标准异常类的头文件 using namespace std; // 一个可能抛出异常的函数:计算除法 double divide(double a, double b) { // 检测异常条件:除数为0 if (b == 0) { // 抛出异常:throw 后面是异常对象(可以是自定义值/标准异常) throw invalid_argument("除数不能为0!"); // 标准异常类,带错误信息 } return a / b; } int main() { double num1 = 10, num2 = 0; // 1. try块:包裹可能抛出异常的代码 try { double result = divide(num1, num2); cout << "计算结果:" << result << endl; } // 2. catch块:捕获并处理对应类型的异常 catch (const invalid_argument& e) { // 匹配throw抛出的异常类型 cout << "捕获到异常:" << e.what() << endl; // what()获取异常描述 } // 3. 万能catch:捕获所有类型的异常(可选) catch (...) { cout << "捕获到未知异常!" << endl; } // 异常处理后,程序继续执行 cout << "程序未崩溃,正常结束~" << endl; return 0; } 代码运行结果:
plaintext
捕获到异常:除数不能为0! 程序未崩溃,正常结束~ 关键语法解释:
try块:必须有,里面放 “可能出问题” 的代码(比如调用 divide 函数)。throw抛出异常:当检测到错误时,用throw主动 “扔出” 一个异常(可以是 int、string、标准异常类等),程序会立刻跳转到对应的 catch 块,不再执行 throw 后面的代码。catch捕获异常:- 紧跟 try 块,
catch(类型& e)里的 “类型” 必须和 throw 抛出的类型匹配; ...是万能捕获,能接住所有类型的异常(建议最后加,防止漏捕导致程序崩溃);e.what()是标准异常类的成员函数,返回异常的描述字符串。
- 紧跟 try 块,
三、常用的标准异常类(不用自己造轮子)
C++ 标准库提供了一系列现成的异常类,直接用更规范,常见的有:
| 异常类 | 用途 | 示例场景 |
|---|---|---|
invalid_argument | 无效参数 | 除数为 0、传入非法字符 |
out_of_range | 越界访问 | 数组 / 字符串下标越界 |
bad_alloc | 内存分配失败 | new 关键字申请内存失败 |
runtime_error | 运行时错误(自定义描述) | 文件打开失败 |
示例:用out_of_range处理数组越界:
cpp
运行
#include <iostream> #include <stdexcept> #include <vector> using namespace std; int getElement(vector<int>& vec, int index) { if (index < 0 || index >= vec.size()) { throw out_of_range("数组下标越界!"); } return vec[index]; } int main() { vector<int> nums = {1,2,3}; try { cout << getElement(nums, 5) << endl; // 下标5越界 } catch (const out_of_range& e) { cout << "异常:" << e.what() << endl; } return 0; } 四、为什么要用异常处理?
对比传统的 “返回错误码”(比如用 - 1 表示失败),异常处理的优势:
- 错误和业务逻辑分离:不用在代码里到处写
if (返回值 == -1),错误处理集中在 catch 块,代码更整洁; - 能跨函数传递:throw 抛出的异常可以穿过多层函数调用,直接被上层的 catch 捕获(比如函数 A 调用 B,B 调用 C,C 抛出异常,A 里的 catch 能接住);
- 强制处理错误:如果抛出异常但没被 catch,程序会调用
terminate()直接崩溃,避免 “隐性错误”(比如返回错误码但程序员忘了判断)。
五、新手注意事项
- 不要用异常处理替代正常的逻辑判断(比如循环结束条件),只处理 “意外情况”;
- 抛出异常时尽量用标准异常类,而非 int/string,可读性和规范性更好;
- catch 块里尽量按 “具体异常在前,万能异常在后” 的顺序写,否则万能 catch 会先捕获,具体 catch 就失效了;
- 异常处理会有轻微的性能开销,但对普通程序几乎无影响,不用过度担心。
总结
- C++ 异常处理核心是
try(包裹风险代码)+throw(抛出异常)+catch(捕获处理),能避免程序崩溃,优雅处理运行时错误; - 优先使用标准异常类(如
invalid_argument、out_of_range),让代码更规范; - 异常处理适合处理 “意外错误”,而非正常逻辑判断,核心优势是错误与业务代码分离。