当前位置: 首页 > news >正文

C++异常的深入了解

C++ 异常是处理运行时错误的标准化机制,核心价值是将「错误检测」与「错误处理」解耦,彻底替代传统的错误码返回方式,让代码逻辑更清晰、健壮。

1.异常概念

异常(Exception)是 C++ 中用于处理程序运行时错误的一种机制。当程序遇到无法正常执行的情况(如除以零、内存分配失败等),可以通过抛出异常中断当前流程,并由专门的异常处理代码捕获和处理。

2.异常的三要素

C++ 异常通过三个关键字实现:try、throw、catch

基础语法:

#include <iostream> using namespace std; void test(int a) { // 1. throw:抛出异常对象(任意类型,推荐类类型) if (a == 0) throw "除数不能为零!"; // 抛字符串 if (a < 0) throw invalid_argument("负数不合法!"); // 抛标准异常 cout << 100 / a << endl; } int main() { try { // 2. try:包裹「可能抛出异常」的代码 test(0); } // 3. catch:捕获匹配类型的异常 catch (const char* e) { cout << "捕获字符串异常:" << e << endl; } catch (const invalid_argument& e) { cout << "捕获标准异常:" << e.what() << endl; } return 0; }

核心规则:
1.try 块:仅包裹可能出错的代码,无异常则正常执行;
2.throw:抛出后立即中断当前执行流,不会执行后续代码;
3.catch:按类型严格匹配异常,捕获后执行处理逻辑。

3.栈展开

这是 C++ 异常最关键的底层机制,也是异常能自动释放资源的根本原因:
1.抛出异常时,程序停止当前执行;
2.从 throw 所在函数开始,逐层回退函数调用栈;
3.每退出一层函数,自动销毁该函数的所有局部对象(调用析构函数);
4.直到找到匹配的 catch 块,程序恢复执行;
5.若全程无匹配 catch,调用 std::terminate 直接终止程序。

代码演示栈展开:

#include <iostream> using namespace std; // 测试对象:构造/析构打印日志 class Test { public: Test() { cout << "Test 构造" << endl; } ~Test() { cout << "Test 析构" << endl; } }; void func2() { Test t; // 局部对象 throw "抛出异常!"; // 抛出异常 cout << "func2 后续代码(不会执行)" << endl; } void func1() { func2(); } int main() { try { func1(); } catch (const char* e) { cout << "捕获异常:" << e << endl; } return 0; }

执行结果:

Test 构造 Test 析构 ✅ 栈展开:自动销毁局部对象 捕获异常:抛出异常!

4.异常捕获的高级规则

1. 类型匹配:无隐式转换
异常捕获不支持隐式类型转换(如 int ↔ double),必须严格匹配类型。
2. 继承类异常:派生类优先捕获
如果抛出派生类异常,catch 必须把派生类写在基类前面,否则会被基类截断(对象切片)。

// 基类异常 class BaseEx {}; // 派生类异常 class DeriveEx : public BaseEx {}; try { throw DeriveEx(); } // ✅ 正确:派生类在前 catch (const DeriveEx& e) { cout << "捕获派生类" << endl; } catch (const BaseEx& e) { cout << "捕获基类" << endl; }

5.万能捕获:catch(...)

捕获所有未匹配的异常,通常用于兜底,避免程序崩溃:

catch (...) { cout << "捕获未知异常!" << endl; // 可以重新抛出:throw; }

推荐:按引用捕获异常
避免对象拷贝,提升性能;
避免继承类的对象切片问题;
标准写法:catch (const 异常类型& e)

谢谢
http://www.gsyq.cn/news/1484987.html

相关文章:

  • 运维开发宝典026-MySQL02数据库表操作
  • 安卓端摄像头实时测心率开发套件(含APP源码、服务端、数据库脚本与实操演示)
  • HC-06蓝牙模块与51单片机串口通信:11.0592MHz和12MHz晶振下的完整配置与调试实录
  • XUnity Auto Translator:彻底打破Unity游戏语言障碍的终极解决方案
  • 2026年实测保姆级指南:查重AIGC爆表?豆包4大神仙指令+3款免费降AI工具降至5%! - 降AI实验室
  • 基于STC89C52的三温区冰箱控制器:带DS18B20测温、机械式除霜检测、数码管/LCD双显示方案
  • 30张实拍舰船图+XML/TXT双标注,开箱即用YOLOv5训练
  • 别再到处找了!我整理了全套Apriltag tag36H11视觉标定图(附高清下载链接)
  • Python中文NLP实战:从预处理避坑到轻量模型部署
  • C# WPF超市收银桌面程序源码包,含UI界面、数据访问层与完整运行截图
  • Open3D GUI踩坑实录:从‘Hello Sphere’到流畅3D界面的五个关键配置
  • 3步解决图像模糊难题:用vectorizer实现PNG/JPG到SVG的无损转换
  • 【MySQL | 第七篇】 索引使用规则
  • 2026年湖州库存管理岗位SCMP四模块报名怎么问?众智商学院冯老师班期资料 - 众智商学院职业教育
  • 【第四十三周】论文阅读《Planning with the Views via Scene Self-Exploration》
  • 别再死磕官方案例了!用FNL数据从零搭建WRF(附避坑指南与完整namelist配置)
  • 别再死磕反正切了!用锁相环PLL从SMO估算的扩展反电动势里提取PMSM转子角度(附Simulink模型)
  • MATLAB R2021b + UE4.25 联合仿真避坑实录:手把手解决插件路径找不到的问题
  • DeepSeek 大模型落地应用与场景实战指南,从客服到代码:10 个 AI 落地场景,重塑企业工作流
  • 数美验证码逆向实战:我是如何一步步破解其滑动验证逻辑的(含关键参数详解)
  • 保姆级教程:用串口助手搞定TMC2209电机驱动,从寄存器读写到CRC校验(附代码)
  • BiSeNet V2保姆级解析:用‘细节+语义’双分支搞定实时分割,附PyTorch复现要点
  • 用 OpenCLAW 重写 CUDA 内核:从异构计算到高性能可移植
  • Langchain-快速入门篇
  • 别再只会调API了!深入理解weixin-js-sdk分享背后的签名与安全机制
  • CH32V307开发板串口服务器实战:基于RT-Thread和LWIP的UART转TCP通信
  • AI 回答又臭又长?原因竟然在于 Markdown
  • 水质监测新趋势:在线光谱仪实时守护碧水蓝天
  • Uber的OED实验智能系统:用贝叶斯优化替代p值决策
  • 告别CAN的奢侈:一文搞懂LIN总线如何用UART接口搞定汽车低速通信