异常(exception)
总示例代码(GESP真题风格:含除零/参数判断)
以下代码覆盖了GESP 4级异常处理的核心知识点,包含除零错误判断、调和平均数(hmean)参数合法性判断等真题常见场景:
#include <iostream>
#include <stdexcept>
using namespace std;
// 场景1:除法运算,判断除零错误(抛出字符串异常)
int divide(int a, int b) {
if (b == 0) {
throw "Division by zero error"; // 抛出const char*类型异常
}
return a / b;
}
// 场景2:计算调和平均数,判断参数合法性(抛出标准异常)
// 调和平均数公式:hmean = 2ab/(a+b),要求 a != -b
double hmean(double a, double b) {
if (a == -b) {
throw runtime_error("hmean: a cannot be equal to -b"); // 抛出标准异常
}
return 2.0 * a * b / (a + b);
}
// 场景3:年龄检查,抛出int类型错误码
void checkAge(int age) {
if (age < 0 || age > 150) {
throw 400; // 抛出int类型错误码
}
cout << "年龄合法:" << age << endl;
}
int main() {
// 1. 测试除零异常
try {
cout << "--- 测试1:除零判断 ---" << endl;
int res = divide(10, 0); // 触发异常
cout << "结果:" << res << endl; // 这行不会执行
} catch (const char* msg) {
cout << "[捕获字符串异常] " << msg << endl;
}
// 2. 测试调和平均数异常
try {
cout << "\n--- 测试2:调和平均数参数判断 ---" << endl;
double val = hmean(10, -10); // 触发异常
cout << "调和平均数:" << val << endl; // 这行不会执行
} catch (const runtime_error& e) {
cout << "[捕获标准异常] " << e.what() << endl;
}
// 3. 测试万能兜底捕获
try {
cout << "\n--- 测试3:万能兜底捕获 ---" << endl;
checkAge(200); // 抛出int类型
} catch (const char* msg) {
cout << "这行不会执行,类型不匹配" << endl;
} catch (...) {
cout << "[万能兜底] 捕获到了未知类型的异常" << endl;
}
return 0;
}一、异常处理机制的核心设计目的
C++的try-catch异常处理机制,唯一核心目的是在程序发生运行时错误时,提供一种结构化的错误处理方式,避免程序直接崩溃,同时将错误处理逻辑与正常业务逻辑分离,提升代码可读性与可维护性。
高频易错排除项
- 异常处理不能提高程序运行速度,反而会带来轻微的运行时开销;
- 异常处理不负责解决编译错误,编译错误由编译器在编译阶段拦截,与异常机制无关;
- 异常处理无法减少程序的内存占用。
二、异常处理的三大核心语法要素
1. try 块
- 作用:包裹可能抛出异常的代码,只有在
try块内抛出的异常,才会被后续的catch块捕获; - 规则:一个
try块可以对应多个catch块,try块必须和至少一个catch块配对使用。
2. throw 语句
- 作用:主动抛出异常,是触发异常处理流程的唯一方式;
规则:通常配合
if判断使用,在检测到非法输入或运行时错误(如除零、参数越界)时抛出。可以抛出任意类型的异常,包括但不限于:- C++标准异常类(如
std::runtime_error,需引入<stdexcept>头文件); - 字符串常量(如
const char*类型); - 基础数据类型(如
int、double等)。
- C++标准异常类(如
3. catch 块
- 作用:捕获并处理
try块中抛出的异常,可编写多个catch块分别处理不同类型的异常; - 特殊语法:
catch(...)是万能兜底捕获块,可以捕获任意类型的异常,必须放在所有具体类型catch块的最后。
三、异常类型的匹配规则
精准匹配原则:
catch块的参数类型必须和throw抛出的异常类型精确匹配,才会进入该catch块执行;- 示例:抛出
std::runtime_error类型异常,只有catch(const std::runtime_error& e)能精准捕获;抛出const char*类型的字符串异常,只有catch(const char* msg)能精准捕获。
- 示例:抛出
- 基类引用可捕获派生类异常:C++标准异常体系中,用基类
const std::exception&可以捕获所有派生自它的标准异常(如runtime_error)。 - 万能捕获的误区:
catch(...)可以捕获任意类型的异常,并非只能捕获某一种特定类型。
四、异常抛出后的程序执行流程
- 一旦
throw抛出异常,立即终止try块中后续所有代码的执行,直接跳转到匹配的catch块; - 匹配到
catch块后,会完整执行该catch块内的所有代码;若catch块内有return,会直接终止函数执行,无return则执行完catch后继续执行后续代码。 - 异常会沿着函数调用链向上传递:函数内抛出的异常,若当前函数无匹配的
catch,会传递给上层调用函数,直到找到匹配的catch,或传递到main函数。
五、未捕获异常的处理机制
- 若抛出的异常没有任何匹配的
catch块,程序不会在编译时报错,而是在运行时调用std::terminate()函数,强制终止程序运行; 核心误区纠正:
- 不是所有异常都必须被捕获,不捕获的后果是程序终止,而非编译失败;
- 未匹配的异常只会在运行时触发程序终止,不会在编译阶段报错。
六、高频易错点汇总
| 说法 | 正确/错误 | 核心原因 |
|---|---|---|
| 如果一个异常在try块中抛出但没有任何catch匹配,它将在编译时报错 | 错误 | 编译不报错,运行时调用std::terminate终止程序 |
catch(...)只能捕获int类型异常 | 错误 | catch(...)是万能捕获,可捕获任意类型异常 |
未捕获异常会调用std::terminate终止程序 | 正确 | C++标准规定,无匹配catch的异常会触发该函数 |
| 如果一个函数可能抛出异常,那么一定要在try子句里调用这个函数 | 错误 | 不放在try中调用,异常会向上传递,并非必须放在try内 |
| 所有异常都必须被捕获,否则程序会崩溃 | 错误 | 不是必须捕获,不捕获的标准行为是调用terminate终止程序 |
评论已关闭