C++中的异常处理机制(try、catch、throw)

发布时间:2026/7/15 10:28:39

C++中的异常处理机制(try、catch、throw)
异常处理它解决的是「代码出错了怎么办」的问题。1. 为什么需要异常处理程序运行时总会遇到各种意外情况文件找不到、内存不够用、数组越界、除以零……这些情况如果不处理程序就会直接崩溃。你可能会说用if判断一下不就行了确实可以但if有一个局限——它只能处理「当前函数」里的错误。如果错误发生在深层嵌套的函数调用中你需要一层一层地把错误信息往上传非常麻烦。异常处理提供了一种更优雅的方式在出错的地方「抛出」异常在合适的地方「捕获」它。错误信息会自动沿着调用链向上传递直到被处理。2. 基本语法try、catch、throwC 的异常处理由三个关键字组成try包裹可能出错的代码throw当检测到错误时「抛出」一个异常catch「捕获」异常并处理2.1 最简单的例子#include iostream using namespace std; int divide(int a, int b) { if (b 0) { throw 除数不能为零; // 抛出异常 } return a / b; } int main() { try { cout divide(10, 2) endl; // 正常执行 cout divide(10, 0) endl; // 会触发异常 cout 这行不会被执行 endl; // 异常后跳过 } catch (const char* msg) { cout 捕获到异常 msg endl; } cout 程序继续正常运行 endl; return 0; }输出5 捕获到异常除数不能为零 程序继续正常运行几个关键点throw抛出异常后try块中剩余的代码不会被执行程序直接跳转到对应的catch块。catch处理完异常后程序继续往下执行不会崩溃。throw后面可以跟任何类型的值字符串、整数、自定义对象等。2.2 多个 catch 块你可以针对不同类型的异常写不同的处理逻辑#include iostream using namespace std; void process(int type) { if (type 1) throw 42; if (type 2) throw 出错了; if (type 3) throw 3.14; } int main() { for (int i 1; i 3; i) { try { process(i); } catch (int e) { cout 整数异常 e endl; } catch (const char* e) { cout 字符串异常 e endl; } catch (double e) { cout 浮点异常 e endl; } } return 0; }输出整数异常42 字符串异常出错了 浮点异常3.14catch块会按照书写的顺序匹配异常类型只会执行第一个匹配的catch块。3. 标准异常类在实际开发中我们通常不会throw裸字符串或整数而是使用 C 标准库提供的异常类。它们都在stdexcept头文件中。3.1 常见的标准异常异常类用途std::runtime_error运行时错误如文件不存在std::invalid_argument无效参数std::out_of_range越界访问std::overflow_error算术溢出std::logic_error逻辑错误3.2 使用标准异常#include iostream #include stdexcept #include vector using namespace std; int getElement(const vectorint vec, int index) { if (index 0 || index vec.size()) { throw out_of_range(下标 to_string(index) 越界); } return vec[index]; } int main() { vectorint nums {10, 20, 30}; try { cout getElement(nums, 1) endl; // 20 cout getElement(nums, 5) endl; // 越界 } catch (const out_of_range e) { cout 异常 e.what() endl; } return 0; }输出20 异常下标 5 越界标准异常类都有一个what()方法返回错误描述信息。用const 引用const exception来捕获是一个好习惯可以避免不必要的拷贝。3.3 统一捕获所有异常如果不确定会抛出什么类型的异常可以用catch (...)捕获所有异常try { // 可能出错的代码 } catch (const exception e) { cout 标准异常 e.what() endl; } catch (...) { cout 未知异常 endl; }建议把catch (const exception)放在前面catch (...)放在最后作为兜底。4. 自定义异常类当标准异常类不能满足需求时你可以定义自己的异常类。通常的做法是继承std::exception#include iostream #include exception #include string using namespace std; class MyException : public exception { private: string message; public: MyException(const string msg) : message(msg) {} const char* what() const noexcept override { return message.c_str(); } }; void riskyOperation() { throw MyException(自定义异常操作失败); } int main() { try { riskyOperation(); } catch (const MyException e) { cout e.what() endl; } return 0; }输出自定义异常操作失败自定义异常的好处是你可以携带更多的上下文信息比如错误代码、发生位置等方便调试和日志记录。5. 异常的传播机制理解异常是怎么「传递」的对于正确使用异常处理至关重要。5.1 调用链中的异常传播#include iostream #include stdexcept using namespace std; void funcC() { throw runtime_error(funcC 中出错了); } void funcB() { funcC(); // 不处理继续向上传 } void funcA() { try { funcB(); // 不处理继续向上传 } catch (const runtime_error e) { cout funcA 捕获 e.what() endl; } } int main() { funcA(); return 0; }输出funcA 捕获funcC 中出错了异常从funcC抛出经过funcB没有catch最终在funcA中被捕获。异常会沿着调用链自动向上传递直到找到匹配的catch块。5.2 没有被捕获的异常如果异常一路传到main函数都没有被捕获程序会调用std::terminate()直接终止并可能弹出系统级的错误提示。所以一定要确保所有可能抛出异常的地方都有对应的catch处理。6. RAIIC 资源管理的黄金法则异常处理有一个容易被忽视的问题资源泄漏。如果在try块中申请了内存或打开了文件异常发生后这些资源可能不会被释放。C 的解决方案是RAIIResource Acquisition Is Initialization——把资源的生命周期绑定到对象的生命周期上。当对象离开作用域时析构函数会自动释放资源即使是因为异常导致的离开。#include iostream #include fstream #include stdexcept using namespace std; void processFile(const string filename) { ifstream file(filename); // RAII文件在构造时打开 if (!file.is_open()) { throw runtime_error(无法打开文件 filename); } string line; while (getline(file, line)) { cout line endl; } // 函数结束时file 的析构函数自动关闭文件 // 即使中途抛出异常析构函数也会被调用 } int main() { try { processFile(test.txt); } catch (const runtime_error e) { cout 错误 e.what() endl; } return 0; }STL 容器vector、string等和智能指针unique_ptr、shared_ptr都遵循 RAII 原则。在 C 中优先使用 RAII 管理资源而不是手动new/delete或open/close。7. 使用异常的最佳实践7.1 什么时候该用异常真正的异常情况文件不存在、网络断开、内存不足等不可预期的错误不适合正常流程控制不要用异常来代替if-else判断7.2 异常安全的三个级别级别保证说明基本保证程序不会泄漏资源最低要求强保证操作要么完全成功要么回到操作前的状态事务性不抛出保证函数保证不抛出异常用noexcept声明7.3 使用noexcept标记不抛出异常的函数如果你确定某个函数不会抛出异常可以用noexcept声明帮助编译器做更好的优化int add(int a, int b) noexcept { return a b; }析构函数默认就是noexcept的你不应该在析构函数中抛出异常。8. 总结C 的异常处理机制try包裹可能出错的代码throw抛出异常catch捕获并处理。标准异常类runtime_error、out_of_range等提供了统一的错误描述接口。异常沿着调用链自动向上传递直到被catch捕获。RAII 是 C 资源管理的核心原则确保异常发生时资源不会泄漏。异常只用于处理真正的异常情况不要用来做流程控制。异常处理是编写健壮程序的重要保障。

相关新闻

AI 多轮对话状态机:不是所有聊天都需要无限轮次

AI 多轮对话状态机:不是所有聊天都需要无限轮次

2026/7/9 0:58:12

AI 多轮对话状态机:不是所有聊天都需要无限轮次 一、多轮对话的产品陷阱是越聊越散 AI 陪伴类产品常把"支持无限轮次对话"当作卖点。但在实际使用中,超过5轮的对话往往会发散。用户的话题从一个方向漂到另一个方向,模型为了保持连贯…

计算机毕业设计之基于贝叶斯算法的共享单车热点区需求预测

计算机毕业设计之基于贝叶斯算法的共享单车热点区需求预测

2026/7/9 1:43:55

共享单车作为一种新兴的城市交通工具,已在全球范围内得到广泛应用。随着城市化进程的加快,共享单车已成为解决城市交通拥堵、减少空气污染的重要手段。然而,共享单车的无序停放问题也带来了城市管理的新挑战。针对共享单车需求预测的问题&…

移动端部署EmbeddingGemma-300M:5个核心技巧实现离线语义搜索

移动端部署EmbeddingGemma-300M:5个核心技巧实现离线语义搜索

2026/7/8 21:22:53

1. 项目概述:为什么要在移动端跑EmbeddingGemma-300M?最近在折腾移动端AI应用的朋友,估计都绕不开一个词:RAG(检索增强生成)。简单说,就是让AI在回答你问题前,先在自己的知识库里搜一…

ROS机器人系统开发:yocto-meta-ros在OpenEuler上的应用案例

ROS机器人系统开发:yocto-meta-ros在OpenEuler上的应用案例

2026/7/15 10:18:50

ROS机器人系统开发:yocto-meta-ros在OpenEuler上的应用案例 【免费下载链接】yocto-meta-ros ROS (Robot Operating System) support layer 项目地址: https://gitcode.com/openeuler/yocto-meta-ros 前往项目官网免费下载:https://ar.openeuler.…

运放噪声分析与低噪声电路设计实践

运放噪声分析与低噪声电路设计实践

2026/7/15 10:18:50

1. 运放噪声的本质与分类运放噪声就像电子电路中的"背景杂音",它无时无刻不在影响着信号的纯净度。作为一名硬件工程师,我处理过太多因为忽视噪声而导致系统性能下降的案例。运放手册中的噪声参数看似简单,实则暗藏玄机。运放噪声主…

openEuler/embedded镜像多样化实践:Docker与开发者镜像使用指南

openEuler/embedded镜像多样化实践:Docker与开发者镜像使用指南

2026/7/15 10:18:50

openEuler/embedded镜像多样化实践:Docker与开发者镜像使用指南 【免费下载链接】embedded The openEuler support for embedded device 项目地址: https://gitcode.com/openeuler/embedded 前往项目官网免费下载:https://ar.openeuler.org/ar/ …

3分钟快速上手:ncmdumpGUI让你的网易云音乐NCM格式转换如此简单

3分钟快速上手:ncmdumpGUI让你的网易云音乐NCM格式转换如此简单

2026/7/15 10:18:50

3分钟快速上手:ncmdumpGUI让你的网易云音乐NCM格式转换如此简单 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换,Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 还在为网易云音乐下载的歌曲只能在…

uos-exporter数据库监控:ClickHouse、Redis、Elasticsearch全方位监控

uos-exporter数据库监控:ClickHouse、Redis、Elasticsearch全方位监控

2026/7/15 10:18:49

uos-exporter数据库监控:ClickHouse、Redis、Elasticsearch全方位监控 【免费下载链接】uos-exporter uos-exporter collects metrics from os 项目地址: https://gitcode.com/openeuler/uos-exporter 前往项目官网免费下载:https://ar.openeuler…

2小时掌握Pandas数据分析:从数据处理到可视化实战

2小时掌握Pandas数据分析:从数据处理到可视化实战

2026/7/15 10:08:49

在日常数据处理工作中,你是否遇到过这样的困扰:Excel处理大量数据时卡顿严重,SQL查询结果需要进一步分析时操作繁琐,或者需要从多个数据源整合信息时手动操作效率低下?这些问题都可以通过Python的Pandas库得到完美解决…

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

2026/7/14 10:03:09

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator XUnity.AutoTranslator作为Unity游戏社区中最成熟的文本翻译解决方…

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

2026/7/13 20:43:19

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持 【免费下载链接】raspberrypi-kernel It provides openEuler kernel source for Raspberry Pi 项目地址: https://gitcode.com/openeuler/raspberrypi-kernel 前往项目官网免费下载&…

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

2026/7/15 0:26:43

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧 【免费下载链接】integration-test The repo contains test suits for system integration test 项目地址: https://gitcode.com/openeuler/integration-test 前往项目官网免费下载:…

【LINUX】驱动

【LINUX】驱动

2026/7/15 0:08:14

【LINUX驱动】【字符设备】【中断】【Platform】【网课 设备树】【GPIO】【PINCTRL】【INPUT】【IIC】【SPI】【网络驱动】【屏幕驱动】【一 设备树】【二 内核模块编译】【三 基本驱动框架】【四 Platform总线设备驱动框架】【五 驱动子系统】【六 综合】

【1982-2026】全国高精度建筑轮廓|村级精度|SHP矢量

【1982-2026】全国高精度建筑轮廓|村级精度|SHP矢量

2026/7/15 0:08:14

🔍 数据简介 本次分享1982-2026年全国村级精度建筑轮廓矢量数据,覆盖全国各省市区县,到村级别精细,为2026年最新实时采集成果,非网传仅60/77个城市的老旧数据。 数据含带高度/不带高度双版本,单体建筑边界精…

【1975-2026】全国水系水路数据|河流/水库/运河|SHP矢量

【1975-2026】全国水系水路数据|河流/水库/运河|SHP矢量

2026/7/15 0:08:14

🔍 数据简介 本次分享1975-2026年全国高精度水系水路矢量数据,覆盖全国全域,包含河流、水系、水库、运河、湿地、冰川、沟渠等全类别水文要素。 数据集包含双层矢量图层,字段分类清晰、要素齐全,支持2013-2026逐年完整…