news 2026/4/25 21:41:42

掌握C++异常处理:从基础到高级实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
掌握C++异常处理:从基础到高级实践

C++异常处理详解

1. 异常处理基础

异常是程序运行时发生的非正常情况,如除零错误、内存访问越界等。C++通过trycatchthrow机制实现异常处理:

try { // 可能抛出异常的代码 if (denominator == 0) { throw std::runtime_error("Division by zero"); } result = numerator / denominator; } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; }
2. 异常类型体系

C++标准库提供异常类层次结构:

  • 基类:std::exception
  • 派生类:
    • std::runtime_error(运行时错误)
    • std::logic_error(逻辑错误)
    • std::bad_alloc(内存分配失败)
    • std::out_of_range(越界访问)
class CustomError : public std::runtime_error { public: CustomError(const std::string& msg) : std::runtime_error("Custom: " + msg) {} }; // 使用示例 throw CustomError("Invalid parameter");

l

3. 异常安全保证

分为三个等级:

  1. 基本保证:资源不泄漏,对象处于有效状态
  2. 强保证:操作完全成功或回滚到原始状态
  3. 不抛保证:操作绝不抛出异常(noexcept
// 强保证示例 void safe_swap(T& a, T& b) noexcept { T temp(std::move(a)); a = std::move(b); b = std::move(temp); }
4. RAII资源管理

资源获取即初始化(RAII)是异常安全的核心:

class FileHandler { public: FileHandler(const std::string& path) : file_(fopen(path.c_str(), "r")) { if (!file_) throw std::ios_base::failure("File open failed"); } ~FileHandler() { if (file_) fclose(file_); } // 禁用拷贝 FileHandler(const FileHandler&) = delete; FileHandler& operator=(const FileHandler&) = delete; private: FILE* file_; }; // 使用示例 try { FileHandler fh("data.bin"); // 自动资源释放 } catch (...) { /* 处理异常 */ }
5. 异常规范(C++11后)
  • noexcept声明不抛出异常
  • noexcept(expr)条件性声明
  • 违反noexcept会导致std::terminate调用
void critical_function() noexcept { // 此函数保证不抛出异常 }
6. 异常处理最佳实践
  1. 避免过度使用:仅处理非预期错误
  2. 按引用捕获catch (const ExceptionType& e)
  3. 避免异常屏蔽:析构函数默认设为noexcept
  4. 使用标准异常类型:保持异常层次清晰
  5. 异常中立:允许异常在调用链中传播
// 异常传播示例 void inner() { throw std::logic_error("Error"); } void outer() { try { inner(); } catch (...) { std::throw_with_nested(std::runtime_error("Outer failed")); } } int main() { try { outer(); } catch (const std::exception& e) { std::cerr << "Caught: " << e.what() << std::endl; } }
7. 异常与性能
  • 正常执行路径无性能开销
  • 抛出异常时开销较大(约10-100倍函数调用)
  • 适用场景:
    • 错误处理路径不频繁
    • 错误需要跨多层调用栈处理
    • 替代错误码使代码更清晰

性能对比(纳秒/操作):

操作类型正常流程异常流程
返回错误码5ns-
抛出异常3ns300ns
8. 常见陷阱
  1. 切片问题
try { throw DerivedError(); } catch (BaseError e) { /* 发生对象切片 */ } // 错误 catch (const BaseError& e) { /* 正确 */ } // 正确
  1. 异常丢失
~Resource() noexcept { // 默认noexcept cleanup(); // 若此处抛出异常,程序终止 }
  1. 双重抛出
catch (...) { throw; // 正确:重新抛出原异常 // throw new_exception; // 错误:覆盖原异常 }
9. C++17改进
  1. std::terminate_handler自定义终止行为
  2. std::uncaught_exceptions()检测未处理异常数量
  3. 嵌套异常支持:
try { /* ... */ } catch (...) { std::throw_with_nested( std::runtime_error("Additional context") ); }
10. 与错误码对比
特性异常错误码
跨函数传播自动手动检查返回值
错误信息丰富(类型+消息)有限(通常为整数)
性能开销抛出时高,正常路径无每次调用都需检查
适用场景不可恢复错误频繁发生的可恢复错误
// 错误码示例 std::error_code ec; auto result = risky_operation(ec); if (ec) { /* 处理错误 */ }
结论

C++异常处理提供强大的错误管理机制,但需遵循最佳实践:

  1. 将异常用于非预期错误
  2. 结合RAII保证资源安全
  3. 优先使用标准异常类型
  4. 注意noexcept规范的使用
  5. 避免在析构函数和内存分配失败时抛出异常

正确使用异常可使代码更健壮,同时保持主逻辑的清晰性,是构建可靠C++系统的关键组件。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/25 21:37:51

【A11】身份证号无损压缩到48位的Rust实现

方案概述 将18位身份证号&#xff08;含校验码&#xff09;压缩为48位整数&#xff08;可存储在u64的低48位&#xff09;&#xff0c;布局如下&#xff1a;字段位宽说明addr20 bits行政区划编码&#xff08;高3位0表示非大陆&#xff0c;否则为大陆&#xff09;date18 bits出生…

作者头像 李华
网站建设 2026/4/25 21:33:25

HX711数据不稳定问题

根本原因&#xff1a;PC14/PC15 是 STM32F1 的 OSC32 晶振引脚&#xff0c;即使不启用 LSE&#xff0c;这两个引脚也受备份域保护&#xff0c;有以下严重限制&#xff1a; 最大输出频率仅 3MHz&#xff08;无法可靠驱动 SCK&#xff09; 驱动能力极弱&#xff08;最大灌电流仅 …

作者头像 李华
网站建设 2026/4/25 21:29:31

光伏四可装置设备性能评估:光伏组件衰减率与逆变器效率监测

光伏组件与逆变器作为光伏系统能量转换、传输的核心设备&#xff0c;其运行性能直接决定系统发电效率、生命周期收益及安全稳定性。光伏四可装置&#xff08;可观、可测、可控、可调&#xff09;通过构建精准的性能评估体系&#xff0c;实现组件衰减率与逆变器效率的全周期监测…

作者头像 李华
网站建设 2026/4/25 21:26:02

商超装修吊楣装饰铝拉网现场复尺

做工程采购这几年&#xff0c;我见过太多供应商在展厅里把样品吹得天花乱坠&#xff0c;一到项目现场就原形毕露。装饰金属网这行尤其如此——材料属性、表面处理、加工精度、交付周期&#xff0c;任何一环出问题&#xff0c;工地上几十号人都得等你。后来我养成了个习惯&#…

作者头像 李华
网站建设 2026/4/25 21:24:39

【数据结构精讲】线性表四大核心:数组 / Vector、栈、队列、链表(原理 + 模板 + 避坑 + 选型)

一、线性表基础定义线性表是n 个数据元素的有限序列&#xff0c;元素之间满足「一对一」的前驱后继关系&#xff0c;除首尾元素外&#xff0c;每个元素有且仅有一个前驱和一个后继。本文聚焦线性表的四大核心实现&#xff1a;数组 / Vector、栈、队列、链表&#xff0c;从底层原…

作者头像 李华