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

C++异常处理深度解析:标准库异常类与最佳实践

C++异常处理深度解析:标准库异常类与最佳实践

思维导图概览

C++异常处理
异常处理机制
标准异常类
自定义异常
异常规范
try-catch块
throw
exception基类
逻辑异常
运行时异常
继承exception
重写what
动态异常规范
noexcept

目录

  1. 异常处理基础
  2. 标准异常类体系
  3. 自定义异常类实现
  4. 异常规范详解
  5. 栈操作异常处理实例
  6. 异常处理最佳实践
  7. 常见问题与解决方案

1. 异常处理基础

异常处理是C++处理运行时错误的机制,核心组件包括:

  • try:标识可能抛出异常的代码块
  • throw:抛出异常对象
  • catch:捕获并处理特定类型的异常
#include <iostream>
using namespace std;double divide(double a, double b) {if (b == 0) {throw "Division by zero!"; // 抛出异常}return a / b;
}int main() {try {cout << divide(10, 2) << endl;cout << divide(5, 0) << endl; // 将抛出异常}catch (const char* msg) { // 捕获异常cerr << "Error: " << msg << endl;}return 0;
}

输出结果:

5
Error: Division by zero!

2. 标准异常类体系

C++标准库提供了丰富的异常类,都继承自std::exception基类:

主要异常类别

异常类别包含的异常类典型使用场景
逻辑错误logic_error, invalid_argument程序逻辑错误
运行时错误runtime_error, range_error无法预测的外部条件
内存错误bad_alloc, bad_cast动态内存分配/类型转换失败

常用异常类详解

#include <stdexcept>
#include <vector>void testExceptions() {try {// 无效参数异常throw invalid_argument("Invalid parameter");}catch (const exception& e) {cerr << "Invalid argument: " << e.what() << endl;}try {// 越界访问异常vector<int> vec = {1, 2, 3};cout << vec.at(5); // 访问越界}catch (const out_of_range& e) {cerr << "Out of range: " << e.what() << endl;}try {// 内存分配失败int* hugeArray = new int[1000000000000];delete[] hugeArray;}catch (const bad_alloc& e) {cerr << "Memory allocation failed: " << e.what() << endl;}
}// 输出结果:
// Invalid argument: Invalid parameter
// Out of range: vector::_M_range_check: __n (which is 5) >= this->size() (which is 3)
// Memory allocation failed: std::bad_alloc

3. 自定义异常类实现

创建自定义异常类需继承std::exception并重写what()方法:

#include <exception>
#include <string>class StackException : public exception {string msg;
public:StackException(const string& message) : msg(message) {}virtual const char* what() const noexcept override {return msg.c_str();}
};class StackFullException : public StackException {
public:StackFullException() : StackException("Stack is full") {}
};class StackEmptyException : public StackException {
public:StackEmptyException() : StackException("Stack is empty") {}
};

4. 异常规范详解

动态异常规范(C++11前)

// 此函数只能抛出int类型异常
void fun1(char* s) throw(int) {if (s == nullptr) {throw 1; // 允许的}// throw "error"; // 编译通过但运行时调用unexpected()
}

C++11新规范

// 不抛出任何异常
void safeFunction() noexcept {// 不会抛出异常
}// 可能抛出特定异常
void riskyFunction() noexcept(false) {throw runtime_error("Something went wrong");
}// 条件性noexcept
template <typename T>
void swap(T& a, T& b) noexcept(noexcept(T())) {// 实现...
}

5. 栈操作异常处理实例

#include <iostream>
#include <stdexcept>
using namespace std;class Stack {enum { MAX_SIZE = 3 };int data[MAX_SIZE];int top = -1;int m_flag = 0; // 0: 正常, 1: 空栈, 2: 满栈public:void push(int value) {if (top >= MAX_SIZE - 1) {m_flag = 2; // 栈满throw StackFullException();}data[++top] = value;m_flag = 0;}int pop() {if (top < 0) {m_flag = 1; // 栈空throw StackEmptyException();}m_flag = 0;return data[top--];}int getStatus() const { return m_flag; }
};int main() {Stack s;try {s.push(10);s.push(20);s.push(30);cout << "Pushed 3 items" << endl;s.push(40); // 将抛出栈满异常}catch (const StackFullException& e) {cerr << "Error: " << e.what() << endl;cout << "Stack status: " << s.getStatus() << " (full)" << endl;}try {cout << "Popped: " << s.pop() << endl;cout << "Popped: " << s.pop() << endl;cout << "Popped: " << s.pop() << endl;s.pop(); // 将抛出栈空异常}catch (const StackEmptyException& e) {cerr << "Error: " << e.what() << endl;cout << "Stack status: " << s.getStatus() << " (empty)" << endl;}return 0;
}

输出结果:

Pushed 3 items
Error: Stack is full
Stack status: 2 (full)
Popped: 30
Popped: 20
Popped: 10
Error: Stack is empty
Stack status: 1 (empty)

6. 异常处理最佳实践

  1. 按引用捕获异常

    try { /* ... */ }
    catch (const exception& e) { // 推荐:避免对象切片cerr << e.what() << endl;
    }
    
  2. 异常安全保证

    • 基本保证:操作失败后对象仍处于有效状态
    • 强保证:操作要么成功要么保持原状态(事务性)
    • 不抛保证:操作保证不抛出异常
  3. 资源管理

    // 使用RAII管理资源
    class FileHandler {FILE* file;
    public:FileHandler(const char* filename) : file(fopen(filename, "r")) {if (!file) throw runtime_error("File open failed");}~FileHandler() { if (file) fclose(file); }// 其他方法...
    };
    
  4. 避免在析构函数中抛出异常

    ~MyClass() noexcept { // 使用noexcepttry {// 清理代码...}catch (...) {// 记录日志但不传播异常}
    }
    

7. 常见问题与解决方案

问题类型解决方案
未捕获异常添加全局异常处理器
异常导致资源泄漏使用RAII模式管理资源
异常类型不匹配使用继承层次和基类捕获
异常安全不足实现强异常保证
异常处理性能开销避免在性能关键路径使用异常

全局异常处理

#include <exception>
#include <cstdlib>void terminateHandler() {cerr << "Uncaught exception! Terminating..." << endl;abort();
}int main() {set_terminate(terminateHandler);throw runtime_error("This will be handled by terminate");return 0;
}

输出结果:

Uncaught exception! Terminating...
Aborted (core dumped)

总结思维导图

异常处理核心
try-catch
throw
标准异常类
exception
logic_error
runtime_error
自定义异常
继承exception
重写what
最佳实践
RAII
按引用捕获
noexcept

关键要点回顾:

  1. 异常处理是C++处理运行时错误的机制,优于错误码
  2. 标准库提供丰富的异常类,均继承自std::exception
  3. 自定义异常类应继承标准异常类并重写what()方法
  4. 动态异常规范(throw(type))已弃用,推荐使用noexcept
  5. RAII模式是保证异常安全的关键技术
  6. 析构函数应声明为noexcept避免异常传播
  7. 全局异常处理器可捕获未处理异常

掌握异常处理技术能显著提高程序的健壮性和可维护性。合理使用异常可以使错误处理代码与正常业务逻辑分离,提高代码可读性和可维护性。


原创技术笔记,转载需注明出处。更多系统编程内容持续更新中…

http://www.lqws.cn/news/567793.html

相关文章:

  • 可达性分析算法Test
  • 矩阵的逆 线性代数
  • rabbitmq springboot 有哪些配置参数
  • 打卡day57
  • WebRTC系列:(一)MacOS开发环境搭建(Vscode + Clangd)
  • Ubuntu开放mysql 3306端口
  • 现代 JavaScript (ES6+) 入门到实战(八):总结与展望 - 成为一名现代前端开发者
  • NLP随机插入
  • 复旦大学经济学院系统思考训练
  • MyBatis批量删除
  • [论文阅读]MISSRce
  • Elasticsearch 索引设计与性能优化实战指南
  • M1芯片最终oracle成功版本拉取方法及配置
  • 二叉树找到下一个中序遍历节点的思路
  • foreach、for in 和for of的区别
  • VMware报错问题解决记录
  • NAND Flash BCH和FTL
  • 聊聊横向移动中的实际技术点 ----- ResponderSMB
  • FastAPI+Sqlite+HTML的登录注册与文件上传系统:完整实现指南
  • 驱动开发系列58 - 揭开内核IRQ框架的神秘面纱
  • 对基尼指数作出的努力
  • jenkins启动报错,一直无法启动
  • 介绍Windows下的由Sysinternals开发的一些小工具
  • 实战篇----利用 LangChain 和 BERT 用于命名实体识别-----完整代码
  • OpenAI 系列大模型发展时间轴与主要特性
  • 用Flink打造实时数仓:生产环境中的“坑”与“解药”
  • Mac homebrew 安装教程
  • linux系统---Nginx反向代理与缓存功能
  • Springboot 集成 SpringState 状态机
  • 代码随想录打卡第一天