C++错误处理异常适用场景及抛出对象选择相关问题咨询
你说的没错,这段简单单函数逻辑里确实用if-else比异常合适,异常本来就不是用来处理这种局部可预见的简单错误的。
问题1:适合用异常而非分支判断的典型场景
- 多层调用栈的错误传递场景
如果错误发生在底层函数,需要向上透传到很多层之外的上层逻辑处理,用返回错误码的方式会让每一层调用都要加判断、透传错误的冗余代码,不仅可读性差还容易漏判。异常可以直接跳过中间层,只在上层需要处理的地方捕获,代码干净很多。
举个简单对比示例:
错误码实现版本:
// 底层计算库 int calc_power(double base, double exp, double& res) { if (exp < 0 && fmod(base, 2) == 0) return -1; // 错误码-1代表负数开偶次方 // 省略计算逻辑 return 0; } // 中间层仿真逻辑 int simulate_physics(double param, double& result) { double pow_res; int ret = calc_power(param, 0.5, pow_res); if (ret != 0) return ret; // 必须手动透传错误码 // 省略其他仿真逻辑 return 0; } // 上层UI交互逻辑 void ui_calculate_click() { double res; int ret = simulate_physics(input_val, res); if (ret == -1) { show_error("负数不能开偶次方"); } }
异常实现版本:
// 底层计算库 double calc_power(double base, double exp) { if (exp < 0 && fmod(base, 2) == 0) throw std::invalid_argument("负数不能开偶次方"); // 省略计算逻辑 } // 中间层仿真逻辑,完全不需要处理错误透传 double simulate_physics(double param) { double pow_res = calc_power(param, 0.5); // 省略其他仿真逻辑 } // 上层UI交互逻辑,统一捕获即可 void ui_calculate_click() { try { double res = simulate_physics(input_val); show_result(res); } catch (const std::invalid_argument& e) { show_error(e.what()); } }
构造函数错误处理场景
构造函数没有返回值,无法通过返回错误码的方式通知调用者初始化失败,这种时候异常是最合理的处理方案。比如你写一个FileReader类,构造的时候要打开指定文件,如果文件不存在、没有权限,直接在构造函数里抛异常,调用者就能感知到初始化失败,避免生成一个半可用的无效对象。低概率高影响的错误场景
比如内存分配失败(C++的new操作符默认就会抛std::bad_alloc异常)、网络连接突然中断这类错误,发生概率极低,但一旦发生正常业务逻辑就完全无法继续执行,用异常不需要在正常执行路径里加大量判断分支,不会影响正常路径的执行效率。
问题2:抛出变量b的合理性分析
你这段代码里直接抛b的做法功能上可以运行,但可读性、可维护性非常差,不推荐:
- 捕获方拿到int值的时候,根本无法区分这个int是错误码还是非法的入参值,小项目自己用还好,放到多人协作的大项目里,其他开发者看到
catch(int c)只会一头雾水,甚至如果多个错误场景都抛int,捕获方完全没法区分错误类型。 - 不推荐自定义整数错误码抛出,C++标准库已经提供了继承自
std::exception的一套标准异常类,你可以直接用,也可以继承它自定义专属异常类,不仅可以携带错误描述,还能通过类型直接区分不同的错误,比抛int好用太多。 - 如果你确实需要在异常里携带非法的参数值,推荐自定义异常类存储对应字段,比直接抛变量合理得多,示例:
#include <stdexcept> #include <iostream> using namespace std; class InvalidDivisorException : public runtime_error { public: int invalid_divisor; InvalidDivisorException(const string& msg, int div) : runtime_error(msg), invalid_divisor(div) {} }; int main() { try { int a = 1; int b; cin >> b; if (b <= 0) throw InvalidDivisorException("除数不能小于等于0", b); int c = a / b; cout << c; } catch (const InvalidDivisorException& e) { cout << e.what() << ",你输入的非法值为:" << e.invalid_divisor; } }
- 如果只是临时写小工具、场景极其简单,直接抛变量也能实现需求,但只要是正式项目都不建议这么写。
内容的提问来源于stack exchange,提问作者jaylse2
相关产品推荐
相关产品推荐

