跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++

C++ 异常处理机制:捕获、自定义与实战

综述由AI生成C++ 异常处理通过 try-catch-throw 机制分离错误检测与处理逻辑。掌握标准异常类使用、自定义异常继承设计以及 noexcept 关键字规范是编写健壮代码的关键。结合文件读写实战案例,演示了 RAII 模式与智能指针在保障异常安全中的应用,并总结了常见错误与最佳实践,帮助开发者提升代码容错能力。

SecGuard发布于 2026/3/21更新于 2026/6/217 浏览
C++ 异常处理机制:捕获、自定义与实战

C++ 异常处理机制:捕获、自定义与实战

核心概念与价值

异常处理是 C++ 中处理程序运行时错误的核心机制,其本质是将'错误检测'与'错误处理'分离。在出错的地方抛出异常,在合适的地方捕获并处理,避免程序直接崩溃。

传统的返回值判断方式存在明显缺陷:返回值可能与合法结果冲突(如 -1 既可能是错误码也可能是计算结果),且需手动检查每个函数返回值,代码冗余且易遗漏。相比之下,异常处理的优势在于错误检测与处理分离,结构清晰;异常可跨函数、跨层级传播,无需逐层传递;还能携带丰富的错误信息。

基本语法与执行流程

C++ 异常处理依赖三个关键字:throw(抛出)、try(尝试)、catch(捕获)。

#include <iostream>
using namespace std;

int divide(int a, int b) {
    if (b == 0) {
        throw string("错误:除数不能为 0!");
    }
    return a / b;
}

int main() {
    int x = 10, y = 0;
    try {
        cout << "尝试执行除法运算..." << endl;
        int result = divide(x, y);
        cout << x << " / " << y << " = " << result << endl;
    } catch (const string& err_msg) {
        cout << "捕获到异常:" << err_msg << endl;
    } catch (...) {
        cout << "捕获到未知异常!" << endl;
    }
    cout << "程序继续执行..." << endl;
    return 0;
}

执行流程拆解:

  1. 程序进入 块,执行可能出错的代码。
try
  • 若发生错误,throw 抛出异常对象,立即终止当前 try 块执行。
  • 程序跳转到最近的匹配 catch 块。
  • 执行 catch 中的处理逻辑后,从 catch 块后继续运行。
  • 注意: catch 块按声明顺序匹配。若将基类异常的 catch 放在派生类之前,派生类异常会被基类捕获,导致后续代码无法执行。因此,务必遵循'派生类在前,基类在后'的原则。

    标准异常库与自定义异常

    C++ 标准库提供了继承自 std::exception 的预定义异常类,常用包括 std::logic_error、std::runtime_error、std::out_of_range 和 std::bad_alloc 等。

    实际开发中,我们常需要自定义异常来体现业务语义。设计自定义异常类时,建议遵循以下原则:

    • 继承自 std::exception 或其派生类。
    • 重写 what() 方法返回描述信息。
    • 提供必要的构造函数。
    • 类名清晰,体现异常类型。
    #include <exception>
    #include <string>
    using namespace std;
    
    class BusinessException : public exception {
    private:
        string err_msg;
    public:
        BusinessException(const string& msg) : err_msg(msg) {}
        const char* what() const noexcept override {
            return err_msg.c_str();
        }
    };
    
    class UserNotFoundException : public BusinessException {
    public:
        UserNotFoundException(int user_id) 
            : BusinessException("用户不存在:ID=" + to_string(user_id)) {}
    };
    
    void query_user(int user_id) {
        if (user_id < 1000 || user_id > 9999) {
            throw UserNotFoundException(user_id);
        }
        cout << "查询成功:用户 ID=" << user_id << endl;
    }
    
    int main() {
        try {
            query_user(123);
        } catch (const UserNotFoundException& e) {
            cout << "业务异常:" << e.what() << endl;
        }
        return 0;
    }
    

    高级特性与安全实践

    noexcept 关键字

    C++11 引入的 noexcept 用于声明函数是否可能抛出异常。相比废弃的异常规格说明,它更简洁且能触发编译器优化。若 noexcept 函数实际抛出异常,程序会调用 std::terminate() 终止,因此需确保该函数确实不会抛出异常。

    异常安全与 RAII

    异常安全要求程序在抛出异常时不泄露资源、保持数据状态一致。推荐使用智能指针(如 std::unique_ptr)和资源获取即初始化(RAII)模式管理资源。例如,文件流对象在析构时会自动关闭,即使中间抛出异常也不会泄漏。

    #include <fstream>
    #include <string>
    using namespace std;
    
    class FileGuard {
    private:
        ofstream file;
    public:
        FileGuard(const string& filename) : file(filename) {
            if (!file.is_open()) throw string("文件打开失败");
        }
        ~FileGuard() { if (file.is_open()) file.close(); }
    };
    
    void write_file(const string& filename) {
        FileGuard f(filename); // 构造时打开
        // ... 写入操作 ...
        // 异常抛出后,f 析构,文件自动关闭
    }
    

    常见错误与最佳实践

    1. 避免过度使用异常:正常控制流(如查找元素未找到)应使用返回值,而非异常。
    2. 按引用捕获:使用 catch (const Exception& e) 避免拷贝开销和对象切片。
    3. 合理组织 catch 顺序:派生类在前,基类在后,兜底 catch(...) 放最后。
    4. 记录异常信息:捕获后记录详细日志,便于排查。
    5. 避免析构函数抛异常:栈展开过程中析构函数抛异常会导致程序终止。

    实战案例:文件读写工具

    下面是一个基于 RAII 的文件读写工具类示例,展示了如何处理文件操作异常并保证资源安全释放。

    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <string>
    #include <exception>
    using namespace std;
    
    class FileException : public exception {
    protected:
        string err_msg;
    public:
        FileException(const string& filename, const string& reason) {
            err_msg = "文件操作异常:文件\"" + filename + "\", 原因:" + reason;
        }
        const char* what() const noexcept override {
            return err_msg.c_str();
        }
    };
    
    class FileHandler {
    private:
        string filename;
        fstream file_stream;
    public:
        FileHandler(const string& filename, ios_base::openmode mode) : filename(filename) {
            file_stream.open(filename, mode);
            if (!file_stream.is_open()) {
                throw FileException(filename, "无法打开文件");
            }
        }
        ~FileHandler() {
            if (file_stream.is_open()) file_stream.close();
        }
        vector<string> read_file() {
            vector<string> content;
            string line;
            while (getline(file_stream, line)) {
                content.push_back(line);
            }
            return content;
        }
        void write_file(const vector<string>& content) {
            for (const string& line : content) {
                file_stream << line << endl;
            }
            file_stream.flush();
        }
    };
    
    int main() {
        try {
            FileHandler reader("input.txt", ios::in);
            auto content = reader.read_file();
            FileHandler writer("output.txt", ios::out | ios::trunc);
            writer.write_file(content);
        } catch (const FileException& e) {
            cout << "错误提示:" << e.what() << endl;
        } catch (const exception& e) {
            cout << "系统错误:" << e.what() << endl;
        }
        return 0;
    }
    

    通过上述实践,我们可以构建健壮、容错能力强的 C++ 程序。掌握异常处理不仅是语法的运用,更是编写高质量工程代码的重要保障。

    目录

    1. C++ 异常处理机制:捕获、自定义与实战
    2. 核心概念与价值
    3. 基本语法与执行流程
    4. 标准异常库与自定义异常
    5. 高级特性与安全实践
    6. noexcept 关键字
    7. 异常安全与 RAII
    8. 常见错误与最佳实践
    9. 实战案例:文件读写工具
    • 💰 8折买阿里云服务器限时8折了解详情
    • Magick API 一键接入全球大模型注册送1000万token查看
    • 🤖 一键搭建Deepseek满血版了解详情
    • 一键打造专属AI 智能体了解详情
    极客日志微信公众号二维码

    微信扫一扫,关注极客日志

    微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

    更多推荐文章

    查看全部
    • 预训练语言模型与 BERT 实战应用
    • 超越 import 与 pip:深入 Python 模块化与依赖管理核心
    • 算法优选:位运算技巧与实战案例
    • Linux 系统目录结构详解
    • Ladybird 独立浏览器架构与 Web 引擎技术介绍
    • Llama 3-8B-Instruct 在昇腾 NPU 上的 SGLang 性能实测
    • 嵌入式 C/C++ 核心知识点整理
    • Python 图形界面与游戏开发实战:计算器、记事本及经典小游戏
    • 从 C 到 Java:面向对象编程核心概念实战
    • 分布式事务与系统一致性:核心方案与实战解析
    • 金融风控文本分析:基于 Llama-Factory 的反欺诈模型训练
    • OpenClaw 机器人本地部署与配置实战
    • LeetCode 141 题:环形链表判断的两种解法
    • 具身智能与视觉:机器人如何“看懂”世界?
    • Spring AI 框架入门:从 DeepSeek 集成到 RAG 实战
    • Segment Anything 论文详解:可提示图像分割基础模型
    • 25 个实用 Prompt 技巧:有效降低 AI 生成内容检测率
    • HTTP 协议核心原理与应用详解
    • Java 中高级面试核心考点解析:集合与线程同步
    • Redis 配置密码不生效的排查与解决方案

    相关免费在线工具

    • Base64 字符串编码/解码

      将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

    • Base64 文件转换器

      将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

    • Markdown转HTML

      将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

    • HTML转Markdown

      将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

    • JSON 压缩

      通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

    • JSON美化和格式化

      将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online