C++ 异常处理

一、异常处理到底是啥?

简单说,异常处理 就是 C++ 里专门用来 “捕获程序运行时意外错误” 的机制。比如程序要打开一个不存在的文件、数组下标越界、内存分配失败这些 “突发情况”,如果不处理,程序会直接崩溃;用异常处理,就能优雅地接住这些错误,让程序继续运行或友好退出。

可以类比成:你点外卖(程序执行),正常情况能收到餐(代码正常跑),但偶尔会遇到 “商家没货”“骑手超时”(异常)—— 异常处理就是让你不用干等着崩溃,而是能选择 “换一家店”“取消订单”(处理异常)。

二、核心语法(怎么用)

C++ 异常处理有 3 个核心关键字:trythrowcatch,三者配合使用,先看完整示例代码:

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! 程序未崩溃,正常结束~ 
关键语法解释:
  1. try:必须有,里面放 “可能出问题” 的代码(比如调用 divide 函数)。
  2. throw 抛出异常:当检测到错误时,用throw主动 “扔出” 一个异常(可以是 int、string、标准异常类等),程序会立刻跳转到对应的 catch 块,不再执行 throw 后面的代码。
  3. catch 捕获异常
    • 紧跟 try 块,catch(类型& e) 里的 “类型” 必须和 throw 抛出的类型匹配;
    • ... 是万能捕获,能接住所有类型的异常(建议最后加,防止漏捕导致程序崩溃);
    • e.what() 是标准异常类的成员函数,返回异常的描述字符串。

三、常用的标准异常类(不用自己造轮子)

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 表示失败),异常处理的优势:

  1. 错误和业务逻辑分离:不用在代码里到处写if (返回值 == -1),错误处理集中在 catch 块,代码更整洁;
  2. 能跨函数传递:throw 抛出的异常可以穿过多层函数调用,直接被上层的 catch 捕获(比如函数 A 调用 B,B 调用 C,C 抛出异常,A 里的 catch 能接住);
  3. 强制处理错误:如果抛出异常但没被 catch,程序会调用terminate()直接崩溃,避免 “隐性错误”(比如返回错误码但程序员忘了判断)。

五、新手注意事项

  1. 不要用异常处理替代正常的逻辑判断(比如循环结束条件),只处理 “意外情况”;
  2. 抛出异常时尽量用标准异常类,而非 int/string,可读性和规范性更好;
  3. catch 块里尽量按 “具体异常在前,万能异常在后” 的顺序写,否则万能 catch 会先捕获,具体 catch 就失效了;
  4. 异常处理会有轻微的性能开销,但对普通程序几乎无影响,不用过度担心。

总结

  1. C++ 异常处理核心是try(包裹风险代码)+throw(抛出异常)+catch(捕获处理),能避免程序崩溃,优雅处理运行时错误;
  2. 优先使用标准异常类(如invalid_argumentout_of_range),让代码更规范;
  3. 异常处理适合处理 “意外错误”,而非正常逻辑判断,核心优势是错误与业务代码分离。

Read more

【数据结构】链表还搞不懂?一文彻底拿下单链表与双链表的所有操作

【数据结构】链表还搞不懂?一文彻底拿下单链表与双链表的所有操作

🔭 个人主页:散峰而望 《C语言:从基础到进阶》《编程工具的下载和使用》《C语言刷题》《算法竞赛从入门到获奖》《人工智能》《AI Agent》 愿为出海月,不做归山云 🎬博主简介 【数据结构】链表还搞不懂?一文彻底拿下单链表与双链表的所有操作 * 前言 * 1. 链表 * 2. 链表的类型 * 2.1 单向或双向 * 2.2 带头或不带头 * 2.3 循环或不循环 * 3. 单链表 * 3.1 定义单链表结构 * 3.2 单链表的打印 * 3.3 插入节点 * 3.3.1 尾插 * 3.3.2 头插 * 3.

By Ne0inhk
Flutter 三方库 shelf_web_socket 的鸿蒙化适配指南 - 实现具备高性能全双工长连接与协议协商能力的端侧服务端架构、支持分布式实时信令与多端协同实战

Flutter 三方库 shelf_web_socket 的鸿蒙化适配指南 - 实现具备高性能全双工长连接与协议协商能力的端侧服务端架构、支持分布式实时信令与多端协同实战

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 shelf_web_socket 的鸿蒙化适配指南 - 实现具备高性能全双工长连接与协议协商能力的端侧服务端架构、支持分布式实时信令与多端协同实战 前言 在进行 Flutter for OpenHarmony 开发时,当我们的鸿蒙应用需要充当“控制中心”角色(如控制智能家居、开启本地调试服务或实现 P2P 实时对抗脚本时),如何在端侧直接拉起一个支持 WebSocket 协议的高性能微服务端?shelf_web_socket 是针对 shelf 后端框架封装的一款官方级 WebSocket 处理器。本文将探讨如何在鸿蒙端构建极致、透明的长连接交互引擎。 一、原直观解析 / 概念介绍 1.1 基础原理 该库本质上是一个 shelf 处理函数(Handler)

By Ne0inhk
《算法闯关指南:动态规划算法--斐波拉契数列模型》--01.第N个泰波拉契数,02.三步问题

《算法闯关指南:动态规划算法--斐波拉契数列模型》--01.第N个泰波拉契数,02.三步问题

🔥草莓熊Lotso:个人主页 ❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受! 🎬 博主简介: 文章目录 * 前言: * 01.第N个泰波拉契数 * 解法(动态规划): * 算法流程: * C++算法代码: * 算法总结&&笔记展示: * 02.三步问题 * 解法(动态规划): * 算法思路: * C++算法代码: * 算法总结&&笔记展示: * 结尾: 前言: 聚焦算法题实战,系统讲解三大核心板块:优选算法:剖析动态规划、二分法等高效策略,学会寻找“最优解”。 递归与回溯:掌握问题分解与状态回退,攻克组合、排列等难题。 贪心算法:理解“

By Ne0inhk