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

C++异常处理完全指南:从原理到实战

异常的基本概念

异常是程序运行时发生的非预期事件(如除零、内存不足)。C++通过try、catch和throw提供结构化处理机制,使程序能够优雅处理错误,而非直接崩溃。

核心思想:将错误处理与正常逻辑分离,提高代码可读性和健壮性。

基本异常抛出与捕获

场景:处理除零错误,抛出并捕获异常。

代码语言:javascript

AI代码解释

#include <iostream> #include <stdexcept> // 标准异常头文件 double divide(double a, double b) { if (b == 0) { throw std::runtime_error("Error: Division by zero!"); } return a / b; } int main() { try { double result = divide(10, 0); std::cout << "Result: " << result << std::endl; } catch (const std::runtime_error& e) { std::cout << "Caught exception: " << e.what() << std::endl; } return 0; } 输出: Caught exception: Error: Division by zero!

说明:

  • throw 抛出一个 std::runtime_error 异常对象。
  • try 块内调用可能抛出异常的代码。
  • catch 捕获特定异常,e.what() 返回错误信息

多类型异常捕获

场景:根据错误类型抛出不同异常,并分别处理。

代码语言:javascript

AI代码解释

#include <iostream> #include <stdexcept> void processInput(int value) { if (value < 0) { throw std::invalid_argument("Negative value not allowed!"); } else if (value > 100) { throw std::out_of_range("Value exceeds limit!"); } // 其他逻辑 } int main() { try { processInput(-5); // 触发invalid_argument } catch (const std::invalid_argument& e) { std::cout << "Invalid Argument: " << e.what() << std::endl; } catch (const std::out_of_range& e) { std::cout << "Out of Range: " << e.what() << std::endl; } catch (...) { std::cout << "Unknown error!" << std::endl; } return 0; } 输出: Invalid Argument: Negative value not allowed!

说明:

  • 多个 catch 块按顺序匹配异常类型。
  • catch (…) 捕获所有未被匹配的异常。

异常重新抛出

场景:中间层捕获异常后记录日志,重新抛出供上层处理。

代码语言:javascript

AI代码解释

#include <iostream> #include <stdexcept> void lowLevel() { throw std::runtime_error("Low-level failure!"); } void highLevel() { try { lowLevel(); } catch (const std::runtime_error& e) { std::cout << "Logged: " << e.what() << std::endl; throw; // 重新抛出当前异常 } } int main() { try { highLevel(); } catch (const std::runtime_error& e) { std::cout << "Main caught: " << e.what() << std::endl; } return 0; } 输出: Logged: Low-level failure! Main caught: Low-level failure!

异常安全

核心原则

  • 基本保证:异常发生后,程序处于有效状态(无资源泄漏)。
  • 强保证:操作要么成功,要么状态回滚到操作前(类似事务)。
  • 无抛出保证:操作绝不抛出异常(如swap)。

场景:使用智能指针确保资源在异常发生时自动释放。

代码语言:javascript

AI代码解释

#include <iostream> #include <memory> #include <stdexcept> class Resource { public: Resource() { std::cout << "Resource acquired.\n"; } ~Resource() { std::cout << "Resource released.\n"; } }; void riskyOperation() { auto res = std::make_unique<Resource>(); // RAII管理 throw std::runtime_error("Oops, something broke!"); // 即使抛出异常,res的析构函数也会被调用 } int main() { try { riskyOperation(); } catch (const std::runtime_error& e) { std::cout << "Error: " << e.what() << std::endl; } return 0; } 输出: Resource acquired. Resource released. Error: Oops, something broke!

说明:

  • RAII(资源获取即初始化)通过对象生命周期管理资源。
  • 智能指针(如 std::unique_ptr)确保内存自动释放。

异常规范(noexcept)

场景:标记不抛出异常的函数。

代码语言:javascript

AI代码解释

#include <iostream> #include <stdexcept> void safeSwap(int& a, int& b) noexcept { // 保证不抛出异常 int temp = a; a = b; b = temp; } int main() { int x = 10, y = 20; safeSwap(x, y); std::cout << "x=" << x << ", y=" << y << std::endl; return 0; } 输出: x=20, y=10

栈展开与析构

场景:异常抛出时,栈展开触发局部对象析构。

代码语言:javascript

AI代码解释

#include <iostream> #include <stdexcept> class Logger { public: Logger() { std::cout << "Logger created.\n"; } ~Logger() { std::cout << "Logger destroyed.\n"; } }; void functionB() { Logger log; // 局部对象 throw std::runtime_error("Error in functionB"); } void functionA() { try { functionB(); } catch (...) { std::cout << "Caught in functionA\n"; throw; } } int main() { try { functionA(); } catch (...) { std::cout << "Caught in main\n"; } return 0; } 输出: Logger created. Logger destroyed. Caught in functionA Caught in main

说明: 栈展开时,log 的析构函数被调用。

标准库异常

  • 提供的一个网站——cplusplus

C++标准库也定义了⼀套⾃⼰的⼀套异常继承体系库,基类是exception,所以我们⽇常写程序,需要在主函数捕获exception即可,要获取异常信息,调⽤what函数,what是⼀个虚函数,派⽣类可以重写。

总结

通过这些例子,你可以看到 C++ 异常处理的不同应用场景,包括:

  • 如何通过 throw 抛出异常,并通过 catch 捕获处理。
  • 通过多个 catch 语句来处理不同类型的异常。
  • 异常的重新抛出以及其应用。
  • 异常安全,如何通过智能指针避免资源泄漏。
  • 如何使用标准库中的异常类来捕获和处理常见的错误。
http://www.cnnetsun.cn/news/2179382.html

相关文章:

  • MCNP5新手避坑指南:从零开始,手把手教你编写第一个蒙特卡罗模拟程序
  • 国家中小学智慧教育平台电子课本下载全攻略:快速获取离线学习资源
  • RTAB-Map:当机器人在未知黑暗中睁开双眼
  • 魔兽争霸III终极优化指南:解决5大常见问题,让经典游戏焕然一新
  • 5分钟掌握:如何在macOS上轻松解密QQ音乐加密格式
  • 科研人必备:2024年最新可用的Sci-Hub镜像站与Nature论文访问指南(附DOI查找技巧)
  • Rainy Aether:构建可验证AI代理的区块链协议与实战指南
  • 低代码应用容器化落地指南(Docker 27专属适配手册)
  • 视觉语言模型的空间感知突破与Perceptio架构解析
  • 进化算法与合成经验学习在自动化代理中的应用
  • 多模态大模型时空推理技术解析与应用实践
  • PyTorch梯度裁剪超简单
  • 并行代理执行框架:提升深度搜索效率的核心技术
  • 手把手教你用Avro-tools.jar:从定义Schema到生成.avro文件的完整流程
  • 刚刚,DeepSeek大更新!多模态终于来了
  • 基于树莓派打造儿童专属学习平板:KidblocksOS系统部署与深度体验
  • Cloudflare 赋予 AI 代理自主创建应用能力,新协议便利背后藏安全运营隐忧
  • 苹果硅芯片 Mac 虚拟化:独特优势与使用限制并存,性能与应用难题待解
  • 终极免费方案:使用applera1n工具完整绕过iOS 15-16激活锁
  • 颠覆存钱贬值观念程序,个人劳动行为铸造成数字凭证,长期确权对抗通胀。
  • 幽冥大陆(一百15)酒店门锁总卡写入故障处理——东方仙盟筑基期
  • 专栏C-产品战略与竞争-04-时机判断
  • 保姆级教程:在Ubuntu 20.04上为i.MX6ULL编译和烧写U-Boot 2016.03(含交叉编译器配置全流程)
  • 告别‘炼丹’黑盒:用HuggingFace Transformers库逐行调试T5模型注意力机制
  • Cadence Allegro 17.4 图层管理保姆级指南:从丝印到阻焊,新手必懂的10个核心层
  • LLM事实一致性评估:挑战、方法与工程实践
  • YOLOv8数据增强新思路:用CoCo数据集“喂饱”你的小样本自定义类别
  • 抖音评论采集神器:无需代码,3步获取完整评论数据的终极指南
  • 太原易碎品搬运
  • VideoSrt:为视频创作者量身打造的字幕自动化解决方案