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 { // 使用noexcept
        try {
            // 清理代码...
        }
        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. 全局异常处理器可捕获未处理异常

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


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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值