目录

c-异常处理2

c++ 异常处理2

以下通过更多具体示例详细说明C++异常处理机制:


一、基础异常处理示例

示例1:基础try-catch结构
#include <iostream>
#include <stdexcept>

void checkAge(int age) {
    if (age < 18) throw std::out_of_range("Age too small");
    if (age > 120) throw std::invalid_argument("Age too large");
}

int main() {
    try {
        checkAge(15);  // 抛出std::out_of_range
    } catch (const std::out_of_range& e) {
        std::cout << "Range Error: " << e.what() << std::endl;
    } catch (const std::exception& e) {
        std::cout << "General Error: " << e.what() << std::endl;
    }
}
/* 输出:
Range Error: Age too small */
示例2:catch(…) 通用捕获
void riskyOperation() {
    throw "Unknown error type"; // 抛出C风格字符串
}

int main() {
    try {
        riskyOperation();
    } catch (const std::exception& e) {
        std::cout << "Standard exception: " << e.what();
    } catch (...) { // 捕获任意类型异常
        std::cout << "Unknown exception caught!";
    }
}
/* 输出:
Unknown exception caught! */

二、栈展开与对象生命周期

示例3:局部对象析构顺序
class Trace {
    int id;
public:
    Trace(int i) : id(i) { std::cout << "Create " << id << "\n"; }
    ~Trace() { std::cout << "Destroy " << id << "\n"; }
};

void funcC() { 
    Trace t3(3);
    throw std::runtime_error("Boom!"); 
}

void funcB() { 
    Trace t2(2); 
    funcC(); 
}

void funcA() { 
    Trace t1(1); 
    funcB(); 
}

int main() {
    try {
        funcA();
    } catch (...) {
        std::cout << "Exception handled\n";
    }
}
/* 输出:
Create 1
Create 2
Create 3
Destroy 3  // 反向析构顺序
Destroy 2
Destroy 1
Exception handled */

三、异常与构造函数

示例4:构造函数部分构造
class Member {
public:
    Member() { std::cout << "Member constructed\n"; }
    ~Member() { std::cout << "Member destroyed\n"; }
};

class Problematic {
    Member m1, m2;
public:
    Problematic() : m1(), m2() {
        throw std::bad_alloc(); // 抛出异常
    }
    ~Problematic() { 
        std::cout << "Problematic destroyed\n"; // 不会执行
    }
};

int main() {
    try {
        Problematic obj;
    } catch (...) {
        std::cout << "Construction failed\n";
    }
}
/* 输出:
Member constructed
Member constructed
Member destroyed  // m2析构
Member destroyed  // m1析构
Construction failed */

四、noexcept关键字的应用

示例5:noexcept函数中的非法操作
void noThrowFunc() noexcept {  // 承诺不抛异常
    throw 42;  // 违反noexcept约定
}

int main() {
    noThrowFunc(); // 触发std::terminate()
}
// 程序直接崩溃,无法捕获异常
示例6:noexcept条件判断
void mayThrow() { throw 42; }
void noThrow() noexcept {}

static_assert(noexcept(noThrow()));    // 通过
static_assert(!noexcept(mayThrow()));  // 通过

template<typename F>
void callSafely(F func) noexcept(noexcept(func())) {
    func();
}

int main() {
    callSafely(noThrow);  // 安全调用
    callSafely(mayThrow); // 若抛出异常,触发terminate
}

五、自定义异常类型

示例7:继承标准异常
#include <exception>
#include <string>

class NetworkException : public std::exception {
    std::string msg;
public:
    NetworkException(const std::string& host) 
        : msg("Connection failed: " + host) {}
    const char* what() const noexcept override {
        return msg.c_str();
    }
};

void connectServer(const std::string& host) {
    throw NetworkException(host);
}

int main() {
    try {
        connectServer("example.com");
    } catch (const NetworkException& e) {
        std::cout << "Network Error: " << e.what();
    }
}
/* 输出:
Network Error: Connection failed: example.com */

六、异常安全与RAII

示例8:文件资源管理
#include <fstream>
#include <vector>

class FileGuard {
    std::fstream file;
public:
    FileGuard(const std::string& name) 
        : file(name, std::ios::out) {
        if (!file) throw std::runtime_error("File open error");
    }
    ~FileGuard() { 
        if (file.is_open()) {
            file.close(); 
            std::cout << "File released\n";
        }
    }
    void write(const std::string& data) {
        file << data;
        if (!file) throw std::runtime_error("Write error");
    }
};

void processFile() {
    FileGuard fg("data.txt");
    fg.write("Hello World");
    throw std::runtime_error("Simulated error after write");
}

int main() {
    try {
        processFile();
    } catch (const std::exception& e) {
        std::cout << "Error: " << e.what() << std::endl;
    }
}
/* 输出:
File released  // 异常发生时自动关闭文件
Error: Simulated error after write */

七、异常重抛与嵌套处理

示例9:异常重抛与上下文添加
void innerFunction() {
    throw std::runtime_error("Original error");
}

void outerFunction() {
    try {
        innerFunction();
    } catch (...) {
        std::cout << "[LOG] Error occurred in innerFunction\n";
        throw;  // 重抛原始异常
    }
}

int main() {
    try {
        outerFunction();
    } catch (const std::runtime_error& e) {
        std::cout << "Caught: " << e.what();
    }
}
/* 输出:
[LOG] Error occurred in innerFunction
Caught: Original error */

总结表格

场景关键行为最佳实践
构造函数异常已构造的成员/基类会被析构,当前对象析构函数不执行使用RAII管理成员资源
析构函数异常若未捕获会导致terminate()析构函数必须标记为 noexcept
异常捕获顺序按catch块顺序匹配,基类异常应放在子类之后先捕获具体异常,后捕获通用异常
noexcept函数违反约定会导致程序终止仅对真正不抛异常的函数使用 noexcept
异常对象通过拷贝初始化,按值/引用捕获影响效率优先使用 const & 捕获异常