跳到主要内容C++ 异常处理机制:异常捕获、自定义异常与实战应用 | 极客日志C++
C++ 异常处理机制:异常捕获、自定义异常与实战应用
C++ 异常处理机制利用 try-catch-throw 实现错误检测与处理分离。核心组件包含 throw 抛出异常、try 定义检测范围、catch 匹配处理逻辑。标准异常库提供 logic_error、runtime_error 等预定义类,自定义异常应继承 std::exception 并重写 what 方法。异常匹配遵循声明顺序,派生类优先于基类。异常安全通过智能指针与 RAII 模式保障资源正确释放。最佳实践涵盖明确使用场景、按引用捕获、合理组织 catch 顺序及避免析构函数抛异常。实战案例演示了文件读写工具类中的异常处理策略与日志记录。
C++ 异常处理机制:异常捕获、自定义异常与实战应用
一、学习目标与重点
- 掌握异常处理的核心概念(异常、抛出、捕获、处理)及基本语法
- 理解 try-catch-throw 语句的执行流程,能够正确捕获和处理标准异常
- 学会自定义异常类,满足实际开发中的个性化异常场景需求
- 掌握异常处理的最佳实践,规避常见错误(内存泄漏、异常安全问题)
- 理解异常规格说明(C++11 前)与 noexcept 关键字的使用场景
- 结合实战案例,提升代码的健壮性和容错能力
💡 核心重点:try-catch 捕获规则、自定义异常的继承设计、异常安全保障、实战场景中的异常处理策略
二、异常处理概述
2.1 什么是异常处理
异常处理是 C++ 中处理程序运行时错误的机制,核心是将错误检测与错误处理分离——在程序出错的地方(如除以零、内存分配失败)抛出异常,在合适的地方(如主函数、业务逻辑层)捕获并处理异常,避免程序直接崩溃,提升代码健壮性。
- 快递配送:快递员(程序执行)配送时发现地址错误(异常),不会直接丢弃快递,而是上报快递公司(抛出异常),由客服(异常处理模块)联系收件人解决(处理异常)
- 餐厅点餐:厨师(程序模块)发现食材耗尽(异常),不会拒绝出餐,而是告知服务员(抛出异常),由服务员(处理模块)向顾客说明并推荐其他菜品(处理异常)
2.2 为什么需要异常处理
在异常处理出现前,程序通常通过返回值判断是否出错,但存在明显缺陷:
int divide(int a, int b) {
if (b == 0) {
return -1;
}
return a / b;
}
int main() {
int result = divide(10, 0);
if (result == -1) {
cout << "除数不能为 0!" << endl;
} else {
cout << "结果:" << result << endl;
}
return 0;
}
- 返回值可能与合法结果冲突(如上述 -1 可能是 divide(-5,5) 的合法结果)
- 需手动检查每个函数返回值,代码冗余且易遗漏
- 错误传播困难(多层函数调用时,需逐层传递错误状态)
- 错误检测与处理分离,代码结构清晰
- 异常可跨函数、跨层级传播,无需逐层传递
- 可携带丰富的错误信息(如错误类型、原因、位置)
- 避免程序因小错误直接崩溃,提升用户体验
2.3 C++ 异常处理的核心组件
- throw:抛出异常(检测到错误时,触发异常)
- try:尝试执行可能抛出异常的代码块(异常检测范围)
- catch:捕获并处理异常(匹配对应的异常类型,执行处理逻辑)
✅ 核心流程:try 块中执行代码 → 若发生错误,throw 抛出异常 → 程序跳转到最近的匹配 catch 块 → 执行 catch 中的处理逻辑 → 处理完成后,程序从 catch 块后继续执行
三、异常处理基本语法与执行流程
3.1 基本语法格式
try {
if (错误条件) {
throw 异常值;
}
}
catch (异常类型 1 异常变量) {
}
catch (异常类型 2 异常变量) {
}
catch (...) {
}
- try 块:必须紧跟一个或多个 catch 块,不能单独存在
- throw 表达式:可抛出任意类型的值(基本类型、字符串、自定义类),抛出后立即终止当前函数执行,跳转到匹配的 catch 块
- catch 块:按顺序匹配异常类型,匹配成功则执行对应处理逻辑;catch (...) 是万能捕获,需放在所有 catch 块最后
- 异常变量:可选(如 catch (int) 可省略变量名),用于获取抛出的异常信息
3.2 执行流程详解
#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;
}
尝试执行除法运算...
捕获到异常:错误:除数不能为 0!
程序继续执行...
执行流程拆解:
- 程序进入 try 块,执行 divide(10, 0)
- divide 函数检测到 b=0,throw 抛出 string 类型异常
- 程序立即终止 try 块执行,跳转到 main 函数中最近的 catch 块
- 第一个 catch 块匹配 string 类型异常,执行处理逻辑(打印错误信息)
- catch 块执行完成后,程序从 catch 块后继续执行(打印'程序继续执行…')
3.3 异常的匹配规则
catch 块按声明顺序匹配异常类型,匹配规则如下:
- 精确匹配:异常类型与 catch 声明类型完全一致(如 throw int(5) 匹配 catch (int))
- 派生类匹配:抛出的派生类异常可被基类类型的 catch 块捕获(如自定义异常类继承自 exception,可被 catch (exception&) 捕获)
- 类型转换匹配:仅支持有限的隐式转换(如 char 可转换为 int,但 int 不能转换为 double)
- catch (...) 匹配所有未被前面 catch 块捕获的异常,必须放在最后
⚠️ 警告:catch 块的声明顺序至关重要,若将基类异常的 catch 块放在派生类之前,会导致派生类异常被基类 catch 块捕获,派生类的 catch 块永远无法执行:
class BaseException {};
class DerivedException : public BaseException {};
try {
throw DerivedException();
} catch (BaseException& e) {
cout << "基类异常" << endl;
} catch (DerivedException& e) {
cout << "派生类异常" << endl;
}
3.4 标准异常库
C++ 标准库提供了一系列预定义的异常类,均继承自 std::exception 基类,定义在 头文件中,常用标准异常如下:
| 异常类 | 描述 | 适用场景 |
|---|
| std::exception | 所有标准异常的基类 | 兜底捕获标准异常 |
| std::logic_error | 逻辑错误(编译期可检测,但未避免) | 如无效参数、非法状态 |
| std::invalid_argument | 无效参数错误 | 如向函数传递非法参数 |
| std::out_of_range | 超出范围错误 | 如数组索引越界、string 下标越界 |
| std::runtime_error | 运行时错误(编译期无法检测) | 如除以零、文件打开失败 |
| std::overflow_error | 溢出错误 | 如数值计算溢出 |
| std::bad_alloc | 内存分配失败错误 | 如 new 分配内存失败 |
#include <iostream>
#include <exception>
#include <vector>
using namespace std;
int main() {
vector<int> nums = {1, 2, 3};
try {
cout << "访问索引 3 的元素:" << nums.at(3) << endl;
} catch (const out_of_range& e) {
cout << "捕获到 out_of_range 异常:" << e.what() << endl;
} catch (const exception& e) {
cout << "捕获到标准异常:" << e.what() << endl;
}
try {
while (true) {
new int[1024 * 1024];
}
} catch (const bad_alloc& e) {
cout << "捕获到 bad_alloc 异常:" << e.what() << endl;
}
return 0;
}
捕获到 out_of_range 异常:vector::_M_range_check: __n (which is 3) >= this->size() (which is 3)
捕获到 bad_alloc 异常:std::bad_alloc
💡 技巧:标准异常类的 what() 方法返回 C 风格字符串(const char*),包含异常的简要描述,可用于日志输出或用户提示。
四、自定义异常类
标准异常类虽能满足常见场景,但实际开发中,我们常需要自定义异常(如业务相关的'用户不存在异常''权限不足异常'),自定义异常类需遵循以下原则:
4.1 自定义异常的设计原则
- 继承自标准异常类(推荐 std::exception 或其派生类),便于统一捕获
- 重写 what() 方法,返回自定义的异常描述信息
- 提供必要的构造函数(默认构造、带错误信息的构造)
- 异常类名清晰,体现异常类型(如 UserNotFoundException)
4.2 自定义异常类的实现
#include <iostream>
#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)) {}
};
class PermissionDeniedException : public BusinessException {
public:
PermissionDeniedException(const string& username, const string& operation)
: BusinessException("权限不足:用户\"" + username + "\"无法执行\"" + operation + "\"操作") {}
};
void query_user(int user_id) {
if (user_id < 1000 || user_id > 9999) {
throw UserNotFoundException(user_id);
}
cout << "查询成功:用户 ID=" << user_id << endl;
}
void execute_sensitive_operation(const string& username) {
if (username != "admin") {
throw PermissionDeniedException(username, "删除数据");
}
cout << "操作成功:用户\"" << username << "\"执行删除数据操作" << endl;
}
int main() {
try {
query_user(123);
} catch (const UserNotFoundException& e) {
cout << "业务异常:" << e.what() << endl;
} catch (const BusinessException& e) {
cout << "业务异常:" << e.what() << endl;
} catch (const exception& e) {
cout << "系统异常:" << e.what() << endl;
}
cout << endl;
try {
execute_sensitive_operation("test");
} catch (const PermissionDeniedException& e) {
cout << "业务异常:" << e.what() << endl;
} catch (const BusinessException& e) {
cout << "业务异常:" << e.what() << endl;
} catch (const exception& e) {
cout << "系统异常:" << e.what() << endl;
}
return 0;
}
业务异常:用户不存在:ID=123
业务异常:权限不足:用户"test"无法执行"删除数据"操作
4.3 自定义异常的优势
- 语义清晰:异常类名直接体现异常类型,代码可读性更高
- 层次分明:通过继承关系组织异常(如业务异常→用户异常→权限异常),便于分类处理
- 信息丰富:可在构造函数中拼接详细的错误信息(如用户 ID、操作名称),便于问题排查
- 兼容标准:继承自 std::exception,可与标准异常一起捕获,统一异常处理逻辑
- 自定义异常类的 what() 方法必须重写为 const noexcept,符合 std::exception 基类的接口规范
- 异常类应尽量轻量,避免复杂的成员变量和构造逻辑(异常抛出时会拷贝异常对象)
- 优先使用引用捕获异常(catch (const Exception& e)),避免拷贝开销,且支持多态匹配
五、异常处理的高级特性
5.1 异常规格说明(C++11 前)与 noexcept
5.1.1 异常规格说明(已废弃)
C++11 前,可通过 throw(类型列表) 声明函数可能抛出的异常类型,称为'异常规格说明':
void func() throw(int, string) {
}
void func2() throw() {
}
- 若函数抛出了异常规格说明之外的异常,会调用 std::unexpected() 函数,默认终止程序
- 编译期不强制检查,仅为程序员提供文档说明,实用性有限
- C++11 已废弃该语法,推荐使用 noexcept 关键字
5.1.2 noexcept 关键字(C++11 及以上)
noexcept 用于声明函数是否可能抛出异常,语法更简洁、功能更明确:
void func() noexcept {
}
void func2() noexcept(false) {
}
template<typename T>
void func3() noexcept(noexcept(T(std::move(T())))) {
}
- 编译器优化:若函数声明为 noexcept,编译器可省略异常处理相关的代码(如栈展开),提升性能
- 明确接口契约:告知调用者该函数无需处理异常,简化调用逻辑
- 影响标准库行为:如 std::vector 的 push_back 若元素的移动构造函数是 noexcept,会使用移动语义(更高效),否则使用拷贝语义
⚠️ 警告:若 noexcept 函数实际抛出了异常,程序会调用 std::terminate() 终止,无法通过 try-catch 捕获,因此需确保 noexcept 函数确实不会抛出异常。
5.2 异常的传播与重新抛出
5.2.1 异常的跨函数传播
异常抛出后,若当前函数没有匹配的 catch 块,异常会向上传播到调用该函数的上层函数,直到找到匹配的 catch 块;若传播到 main 函数仍未捕获,程序会调用 std::terminate() 终止。
#include <iostream>
#include <string>
using namespace std;
void func3() {
cout << "func3:抛出异常" << endl;
throw string("来自 func3 的异常");
}
void func2() {
cout << "func2:调用 func3" << endl;
func3();
cout << "func2:执行完毕(不会执行)" << endl;
}
void func1() {
cout << "func1:调用 func2" << endl;
try {
func2();
} catch (const int& e) {
cout << "func1:捕获 int 类型异常" << endl;
}
cout << "func1:执行完毕" << endl;
}
int main() {
cout << "main:调用 func1" << endl;
try {
func1();
} catch (const string& e) {
cout << "main:捕获 string 类型异常:" << e << endl;
} catch (...) {
cout << "main:捕获未知异常" << endl;
}
cout << "main:程序结束" << endl;
return 0;
}
main:调用 func1
func1:调用 func2
func2:调用 func3
func3:抛出异常
main:捕获 string 类型异常:来自 func3 的异常
main:程序结束
5.2.2 异常的重新抛出
有时需要在 catch 块中处理部分逻辑后,将异常重新抛出给上层函数处理,使用 throw; (不带参数)实现:
#include <iostream>
#include <string>
using namespace std;
void process_data(int data) {
if (data < 0) {
throw string("数据非法:负数不允许");
}
cout << "数据处理成功:" << data << endl;
}
void handle_request(int data) {
try {
process_data(data);
} catch (const string& e) {
cout << "日志记录:发生异常 - " << e << endl;
throw;
}
}
int main() {
try {
handle_request(-5);
} catch (const string& e) {
cout << "用户提示:操作失败,原因:" << e << endl;
}
return 0;
}
日志记录:发生异常 - 数据非法:负数不允许
用户提示:操作失败,原因:数据非法:负数不允许
- throw; 重新抛出的是原始异常对象,不会创建新的异常对象
- 若在 catch 块外使用 throw;, 会抛出 std::bad_exception 异常
- 重新抛出时,异常类型不变,上层函数需按原类型捕获
5.3 异常安全
- 不会发生内存泄漏(已分配的内存被正确释放)
- 数据状态一致(不会出现部分修改的无效状态)
- 资源被正确释放(如文件句柄、网络连接、锁)
5.3.1 常见的异常安全问题
void unsafe_func() {
int* p = new int(10);
process_data(-5);
delete p;
}
5.3.2 异常安全的解决方案
- 使用智能指针(推荐):智能指针(如 std::unique_ptr、std::shared_ptr)会在析构时自动释放内存,即使发生异常也不会泄漏
- 资源获取即初始化(RAII):将资源(如文件、锁)封装在类中,通过构造函数获取资源,析构函数释放资源,利用类的生命周期管理资源
- 使用容器和标准库组件:标准库组件(如 vector、string)均具备异常安全性,避免手动管理资源
#include <iostream>
#include <memory>
#include <string>
using namespace std;
void safe_func() {
unique_ptr<int> p(new int(10));
throw string("测试异常安全");
}
int main() {
try {
safe_func();
} catch (const string& e) {
cout << "捕获异常:" << e << endl;
}
return 0;
}
#include <iostream>
#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("文件打开失败:" + filename);
}
cout << "文件打开成功:" << filename << endl;
}
~FileGuard() {
if (file.is_open()) {
file.close();
cout << "文件关闭成功" << endl;
}
}
void write(const string& content) {
file << content << endl;
}
};
void write_file(const string& filename, const string& content) {
FileGuard file(filename);
file.write(content);
throw string("模拟写入过程中异常");
}
int main() {
try {
write_file("test.txt", "Hello, 异常安全!");
} catch (const string& e) {
cout << "捕获异常:" << e << endl;
}
return 0;
}
文件打开成功:test.txt
文件关闭成功
捕获异常:模拟写入过程中异常
✅ 结论:即使在写入过程中抛出异常,FileGuard 对象会被析构,文件资源被正确释放,实现了异常安全。
六、异常处理的常见错误与最佳实践
6.1 常见错误
错误 1:过度使用异常
将异常用于正常的控制流(如判断函数返回结果),导致代码效率降低、可读性变差:
int find_element(const vector<int>& vec, int target) {
for (int i = 0; i < vec.size(); ++i) {
if (vec[i] == target) {
return i;
}
}
throw string("元素未找到");
}
错误 2:捕获所有异常却不处理
使用 catch (...) 捕获所有异常,但未做任何处理,导致问题排查困难:
try {
risky_operation();
} catch (...) {
}
错误 3:抛出非异常类型的对象
抛出基本类型(如 int、double)或未继承自 std::exception 的自定义类,导致异常处理不统一:
错误 4:异常对象切片
按值捕获异常(catch (BaseException e)),而非按引用捕获,导致派生类异常的特有信息丢失:
class DerivedException : public BaseException {
public:
const char* what() const noexcept override {
return "派生类异常";
}
};
try {
throw DerivedException();
} catch (BaseException e) {
cout << e.what() << endl;
}
6.2 最佳实践
实践 1:明确异常使用场景
仅在'异常情况'(如内存分配失败、非法参数、IO 错误)使用异常,正常控制流(如元素未找到、用户输入错误)使用返回值或其他方式处理。
实践 2:优先使用标准异常或自定义异常类
- 系统级错误(如内存分配、数组越界)使用标准异常类
- 业务级错误(如用户不存在、权限不足)使用自定义异常类,且继承自 std::exception
实践 3:按引用捕获异常
使用 catch (const Exception& e) 捕获异常,避免拷贝开销和对象切片,支持多态匹配。
实践 4:合理组织 catch 块顺序
- 派生类异常的 catch 块放在前面
- 基类异常的 catch 块放在后面
- catch (...) 作为兜底,放在最后,并记录日志或终止程序
实践 5:保证异常安全
- 使用智能指针和 RAII 模式管理资源,避免内存泄漏
- 重要操作(如数据库事务)需实现回滚机制,确保异常发生时数据状态一致
实践 6:记录异常信息
捕获异常后,记录详细的异常信息(如异常类型、错误描述、发生位置、调用栈),便于问题排查。
实践 7:避免在析构函数中抛出异常
析构函数若抛出异常,可能导致程序终止(如在栈展开过程中,析构函数抛出异常会调用 std::terminate()):
class BadClass {
public:
~BadClass() {
throw string("析构函数异常");
}
};
七、实战案例:文件读写的异常处理
7.1 问题描述
实现一个文件读写工具类,支持读取文件内容和写入文件内容,要求:
- 处理文件操作中的常见异常(文件不存在、权限不足、磁盘已满等)
- 使用自定义异常类,提供详细的错误信息
- 保证异常安全(文件资源正确释放)
- 提供友好的用户提示和日志记录
7.2 实现思路
- 自定义文件相关异常类(继承自 std::exception):FileOpenException(文件打开失败)、FileReadException(文件读取失败)、FileWriteException(文件写入失败)
- 基于 RAII 模式实现文件工具类 FileHandler,管理文件流资源
- 实现 read_file 和 write_file 方法,抛出对应的自定义异常
- 在主函数中捕获异常,记录日志并提示用户
7.3 代码实现
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#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 FileOpenException : public FileException {
public:
FileOpenException(const string& filename, const string& reason)
: FileException(filename, "打开失败 - " + reason) {}
};
class FileReadException : public FileException {
public:
FileReadException(const string& filename, const string& reason)
: FileException(filename, "读取失败 - " + reason) {}
};
class FileWriteException : public FileException {
public:
FileWriteException(const string& filename, const string& reason)
: FileException(filename, "写入失败 - " + reason) {}
};
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 FileOpenException(filename, "无法打开文件(可能不存在或权限不足)");
}
cout << "日志:文件\"" << filename << "\"打开成功" << endl;
}
~FileHandler() {
if (file_stream.is_open()) {
file_stream.close();
cout << "日志:文件\"" << filename << "\"关闭成功" << endl;
}
}
vector<string> read_file() {
vector<string> content;
string line;
if (!file_stream.good()) {
throw FileReadException(filename, "文件流状态异常");
}
while (getline(file_stream, line)) {
content.push_back(line);
}
if (file_stream.bad()) {
throw FileReadException(filename, "读取过程中发生 IO 错误");
}
cout << "日志:文件\"" << filename << "\"读取完成,共" << content.size() << "行" << endl;
return content;
}
void write_file(const vector<string>& content) {
if (!file_stream.good()) {
throw FileWriteException(filename, "文件流状态异常");
}
for (const string& line : content) {
file_stream << line << endl;
if (file_stream.fail()) {
throw FileWriteException(filename, "写入数据失败(可能磁盘已满)");
}
}
file_stream.flush();
if (file_stream.fail()) {
throw FileWriteException(filename, "刷新缓冲区失败");
}
cout << "日志:文件\"" << filename << "\"写入完成,共" << content.size() << "行" << endl;
}
};
void print_file_content(const vector<string>& content) {
cout << "\n文件内容:" << endl;
for (int i = 0; i < content.size(); ++i) {
cout << "[" << i + 1 << "] " << content[i] << endl;
}
cout << endl;
}
int main() {
string read_filename = "input.txt";
string write_filename = "output.txt";
try {
FileHandler reader(read_filename, ios::in);
vector<string> content = reader.read_file();
print_file_content(content);
vector<string> new_content = {
"=== 新写入的内容 ===",
"原文件共" + to_string(content.size()) + "行",
"这是第一行新内容",
"这是第二行新内容"
};
FileHandler writer(write_filename, ios::out | ios::trunc);
writer.write_file(new_content);
FileHandler verify_reader(write_filename, ios::in);
vector<string> verify_content = verify_reader.read_file();
print_file_content(verify_content);
} catch (const FileOpenException& e) {
cout << "\n错误提示:" << e.what() << endl;
} catch (const FileReadException& e) {
cout << "\n错误提示:" << e.what() << endl;
} catch (const FileWriteException& e) {
cout << "\n错误提示:" << e.what() << endl;
} catch (const exception& e) {
cout << "\n系统错误:" << e.what() << endl;
} catch (...) {
cout << "\n未知错误:发生未预期的异常" << endl;
}
return 0;
}
7.4 运行结果(正常情况)
日志:文件"input.txt"打开成功
日志:文件"input.txt"读取完成,共 3 行
文件内容:
[1] Hello, File Handling!
[2] This is a test file.
[3] C++ Exception Handling.
日志:文件"input.txt"关闭成功
日志:文件"output.txt"打开成功
日志:文件"output.txt"写入完成,共 4 行
日志:文件"output.txt"关闭成功
日志:文件"output.txt"打开成功
日志:文件"output.txt"读取完成,共 4 行
文件内容:
[1] === 新写入的内容 ===
[2] 原文件共 3 行
[3] 这是第一行新内容
[4] 这是第二行新内容
日志:文件"output.txt"关闭成功
7.5 异常情况测试(如 input.txt 不存在)
错误提示:文件操作异常:文件"input.txt", 原因:打开失败 - 无法打开文件(可能不存在或权限不足)
✅ 结论:该文件工具类通过自定义异常类提供了详细的错误信息,基于 RAII 模式保证了文件资源的正确释放,即使发生异常也不会导致资源泄漏,同时通过分层捕获异常,为用户提供了友好的提示,符合异常处理的最佳实践。
八、总结
- 异常处理是 C++ 处理运行时错误的核心机制,通过 try-catch-throw 实现错误检测与处理的分离,提升代码健壮性。
- 标准异常库提供了一系列预定义异常类(如 out_of_range、bad_alloc),自定义异常类应继承自 std::exception,重写 what() 方法。
- 异常的匹配遵循精确匹配、派生类匹配规则,catch 块需按'派生类在前、基类在后'的顺序声明,catch (...) 作为兜底。
- 异常安全是关键,需通过智能指针、RAII 模式管理资源,避免内存泄漏和数据不一致。
- 最佳实践:明确异常使用场景、按引用捕获异常、记录异常信息、避免在析构函数中抛出异常。
通过本文学习,你应能熟练运用异常处理机制解决实际开发中的错误处理问题,编写健壮、可靠的 C++ 代码。下一篇将深入探讨 C++ 的输入输出流(IO 流),包括文件 IO、字符串 IO 等高级应用!
相关免费在线工具
- 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