Skip to content

异常处理

异常处理是C++中处理运行时错误的机制。本章将介绍try-catch语句、异常类型、自定义异常和异常安全等概念。

基本异常处理

cpp
#include <iostream>
#include <stdexcept>
using namespace std;

int divide(int a, int b) {
    if (b == 0) {
        // 抛出异常
        throw runtime_error("除数不能为0");
    }
    return a / b;
}

int main() {
    // ============ try-catch基本语法 ============
    
    try {
        // 可能抛出异常的代码
        int result = divide(10, 0);
        cout << "结果: " << result << endl;
    }
    catch (const runtime_error& e) {
        // 捕获特定类型的异常
        cerr << "运行时错误: " << e.what() << endl;
    }
    catch (const exception& e) {
        // 捕获标准异常
        cerr << "标准异常: " << e.what() << endl;
    }
    catch (...) {
        // 捕获所有其他异常
        cerr << "未知异常" << endl;
    }
    
    cout << "程序继续执行..." << endl;
    
    return 0;
}

标准异常类型

cpp
#include <iostream>
#include <stdexcept>
#include <vector>
using namespace std;

/*
 * C++标准异常层次结构:
 * 
 * exception(基类)
 * ├── logic_error(逻辑错误,可避免)
 * │   ├── domain_error
 * │   ├── invalid_argument
 * │   ├── length_error
 * │   └── out_of_range
 * ├── runtime_error(运行时错误,难以避免)
 * │   ├── range_error
 * │   ├── overflow_error
 * │   └── underflow_error
 * ├── bad_alloc(内存分配失败)
 * ├── bad_cast(类型转换失败)
 * └── bad_typeid(typeid操作失败)
 */

void testExceptions() {
    // ============ logic_error系列 ============
    
    // invalid_argument:无效参数
    try {
        throw invalid_argument("参数无效");
    }
    catch (const invalid_argument& e) {
        cout << "invalid_argument: " << e.what() << endl;
    }
    
    // out_of_range:越界访问
    try {
        vector<int> v = {1, 2, 3};
        cout << v.at(10) << endl;  // 使用at()会抛出异常
    }
    catch (const out_of_range& e) {
        cout << "out_of_range: " << e.what() << endl;
    }
    
    // length_error:长度错误
    try {
        vector<int> v;
        v.resize(v.max_size() + 1);
    }
    catch (const length_error& e) {
        cout << "length_error: " << e.what() << endl;
    }
    
    
    // ============ runtime_error系列 ============
    
    // runtime_error:运行时错误
    try {
        throw runtime_error("运行时发生错误");
    }
    catch (const runtime_error& e) {
        cout << "runtime_error: " << e.what() << endl;
    }
    
    // overflow_error:溢出错误
    try {
        throw overflow_error("数值溢出");
    }
    catch (const overflow_error& e) {
        cout << "overflow_error: " << e.what() << endl;
    }
    
    
    // ============ 内存相关异常 ============
    
    // bad_alloc:内存分配失败
    try {
        // 尝试分配超大内存
        // int* p = new int[1000000000000];
    }
    catch (const bad_alloc& e) {
        cout << "bad_alloc: " << e.what() << endl;
    }
}

int main() {
    testExceptions();
    return 0;
}

自定义异常

cpp
#include <iostream>
#include <string>
#include <exception>
using namespace std;

// ============ 自定义异常类 ============

// 继承自exception
class MyException : public exception {
private:
    string message;
    int errorCode;
    
public:
    MyException(const string& msg, int code = 0) 
        : message(msg), errorCode(code) {}
    
    // 重写what()方法
    const char* what() const noexcept override {
        return message.c_str();
    }
    
    int getErrorCode() const {
        return errorCode;
    }
};

// 更具体的异常类
class FileException : public exception {
protected:
    string filename;
    string operation;
    
public:
    FileException(const string& file, const string& op)
        : filename(file), operation(op) {}
    
    const char* what() const noexcept override {
        static string msg;
        msg = "文件操作失败: " + operation + " on " + filename;
        return msg.c_str();
    }
    
    const string& getFilename() const { return filename; }
    const string& getOperation() const { return operation; }
};

class FileNotFoundException : public FileException {
public:
    FileNotFoundException(const string& file)
        : FileException(file, "打开") {}
    
    const char* what() const noexcept override {
        static string msg;
        msg = "文件未找到: " + filename;
        return msg.c_str();
    }
};

// ============ 使用自定义异常 ============

void processFile(const string& filename) {
    if (filename.empty()) {
        throw MyException("文件名不能为空", 1001);
    }
    
    if (filename == "notfound.txt") {
        throw FileNotFoundException(filename);
    }
    
    // 模拟文件处理
    cout << "处理文件: " << filename << endl;
}

int main() {
    // 测试自定义异常
    try {
        processFile("");
    }
    catch (const MyException& e) {
        cout << "捕获MyException: " << e.what() << endl;
        cout << "错误码: " << e.getErrorCode() << endl;
    }
    
    try {
        processFile("notfound.txt");
    }
    catch (const FileNotFoundException& e) {
        cout << "\n捕获FileNotFoundException: " << e.what() << endl;
    }
    catch (const FileException& e) {
        cout << "\n捕获FileException: " << e.what() << endl;
    }
    
    return 0;
}

异常安全

cpp
#include <iostream>
#include <memory>
#include <vector>
using namespace std;

// ============ 异常安全级别 ============

/*
 * 异常安全级别:
 * 
 * 1. 无异常安全:可能泄漏资源
 * 2. 基本保证:异常发生时,对象处于有效状态,不会泄漏资源
 * 3. 强保证:异常发生时,状态回滚到操作前(事务语义)
 * 4. 不抛出保证:保证不抛出异常
 */

// ============ RAII资源管理 ============

class FileHandle {
private:
    FILE* file;
    
public:
    FileHandle(const char* filename, const char* mode) {
        file = fopen(filename, mode);
        if (!file) {
            throw runtime_error("无法打开文件");
        }
    }
    
    ~FileHandle() {
        if (file) {
            fclose(file);  // 自动关闭
        }
    }
    
    // 禁止拷贝
    FileHandle(const FileHandle&) = delete;
    FileHandle& operator=(const FileHandle&) = delete;
    
    void write(const string& data) {
        if (fputs(data.c_str(), file) == EOF) {
            throw runtime_error("写入失败");
        }
    }
};

// ============ 强异常安全保证 ============

class Stack {
private:
    vector<int> data;
    
public:
    void push(int value) {
        data.push_back(value);  // vector::push_back提供强保证
    }
    
    int pop() {
        if (data.empty()) {
            throw runtime_error("栈为空");
        }
        
        int value = data.back();
        data.pop_back();  // pop_back不抛出异常
        return value;
    }
    
    // 强保证:交换操作
    void swap(Stack& other) noexcept {
        data.swap(other.data);  // swap不抛出异常
    }
    
    bool empty() const noexcept {
        return data.empty();
    }
};

// ============ 异常安全的函数 ============

// 使用noexcept声明不抛出异常
void safeFunction() noexcept {
    // 保证不抛出异常
    cout << "这是一个不抛出异常的函数" << endl;
}

// 条件noexcept
template<typename T>
void conditionalSwap(T& a, T& b) noexcept(noexcept(a.swap(b))) {
    a.swap(b);
}

int main() {
    // RAII示例
    try {
        FileHandle fh("test.txt", "w");
        fh.write("Hello, World!");
        // 离开作用域时自动关闭文件
    }
    catch (const exception& e) {
        cout << "异常: " << e.what() << endl;
    }
    
    // 强保证示例
    Stack s1, s2;
    s1.push(1);
    s1.push(2);
    s2.push(3);
    
    s1.swap(s2);
    
    cout << "\ns1弹出: ";
    while (!s1.empty()) {
        cout << s1.pop() << " ";
    }
    cout << endl;
    
    return 0;
}

本章小结

本章学习了:

  • 基本异常处理:try-catch-throw语句
  • 标准异常类型:logic_error、runtime_error等
  • 自定义异常:继承exception类
  • 异常安全:RAII、强保证、noexcept

下一章,我们将学习文件操作,了解C++的文件读写操作。