Exception异常处理实战案例
C++异常处理通过try/throw/catch机制分离错误检测与处理。核心内容包括:自定义异常类设计、标准库异常应用、RAII资源管理、跨函数异常传递、多线程协同处理、大型项目异常策略、调试优化技巧等。通过实战案例展示从基础到综合应用的完整流程,提升代码健壮性。
Exception异常处理实战案例
C++异常处理通过try/throw/catch机制分离错误检测与处理。核心内容包括:自定义异常类设计、标准库异常应用、RAII资源管理、跨函数异常传递、多线程协同处理、大型项目异常策略、调试优化技巧等。通过实战案例展示从基础到综合应用的完整流程,提升代码健壮性。
文章目录
第一章:异常处理基础与核心机制
C++异常处理通过try、throw和catch机制实现错误管理,其核心是分离异常检测与处理,提升代码健壮性。try块包裹可能抛出异常的代码,throw触发异常,catch捕获并处理特定类型异常。例如,除法运算中检测分母为零时抛出异常,避免程序崩溃。栈展开机制确保异常沿调用链向上传递,直至匹配的catch块处理。标准库提供std::exception基类,支持自定义异常类型,通过what()方法返回错误信息。理解异常处理流程是实战的基础,为后续章节的复杂场景铺垫。
#include <iostream>
#include <stdexcept>
double safeDivide(double numerator, double denominator) {
if (denominator == 0) {
throw std::runtime_error("除数不能为零");
}
return numerator / denominator;
}
int main() {
try {
double result = safeDivide(10, 0);
std::cout << "结果: " << result << std::endl;
} catch (const std::runtime_error& e) {
std::cerr << "捕获异常: " << e.what() << std::endl;
}
return 0;
}
第二章:自定义异常类的设计与应用
自定义异常类继承std::exception,可扩展错误信息。例如,定义InvalidInput类处理非法输入,重写what()方法返回详细描述。实战中,自定义异常需遵循单一职责原则,避免过度泛化。通过throw抛出对象实例,catch按类型匹配处理。案例:文件操作中,若读取失败抛出FileError,捕获后提示用户。自定义异常提升代码可读性,便于调试和维护。
#include <iostream>
#include <string>
#include <stdexcept>
class FileError : public std::exception {
private:
std::string message;
public:
explicit FileError(const std::string& msg) : message(msg) {}
const char* what() const noexcept override {
return message.c_str();
}
};
void readFile(const std::string& filename) {
// 模拟文件读取失败
throw FileError("无法打开文件: " + filename);
}
int main() {
try {
readFile("nonexistent.txt");
} catch (const FileError& e) {
std::cerr << "文件错误: " << e.what() << std::endl;
}
return 0;
}
第三章:标准库异常与常见场景
C++标准库提供std::runtime_error、std::logic_error等预定义异常,覆盖运行时错误(如内存不足)和逻辑错误(如参数无效)。例如,std::out_of_range处理数组越界。实战中,优先使用标准异常以减少冗余代码。案例:数学运算中,std::domain_error处理无效输入。标准异常简化错误管理,确保跨平台兼容性。
#include <iostream>
#include <vector>
#include <stdexcept>
void accessVector(const std::vector<int>& vec, size_t index) {
if (index >= vec.size()) {
throw std::out_of_range("索引 " + std::to_string(index) +
" 超出向量范围 [0, " +
std::to_string(vec.size()-1) + "]");
}
std::cout << "元素值: " << vec[index] << std::endl;
}
int main() {
std::vector<int> numbers = {1, 2, 3};
try {
accessVector(numbers, 5); // 越界访问
} catch (const std::out_of_range& e) {
std::cerr << "范围错误: " << e.what() << std::endl;
}
return 0;
}
第四章:异常处理中的资源管理
异常可能导致资源泄漏,需结合RAII(资源获取即初始化)机制。例如,使用智能指针管理动态内存,析构时自动释放。try块内分配资源,catch捕获异常后释放。案例:文件操作中,std::ifstream对象在try块内打开文件,异常时析构句柄。RAII确保资源安全,避免手动清理的遗漏。
#include <iostream>
#include <memory>
#include <fstream>
class ResourceManager {
private:
std::unique_ptr<int[]> data;
public:
ResourceManager(size_t size) : data(std::make_unique<int[]>(size)) {
std::cout << "资源分配: " << size << " 个整数" << std::endl;
}
~ResourceManager() {
std::cout << "资源自动释放" << std::endl;
}
};
void processWithRAII() {
ResourceManager manager(100); // RAII管理资源
throw std::runtime_error("模拟处理过程中的异常");
// 异常发生时,manager会自动析构释放资源
}
int main() {
try {
processWithRAII();
} catch (const std::exception& e) {
std::cerr << "异常: " << e.what() << std::endl;
}
return 0;
}
第五章:跨函数异常传递与处理
异常沿调用链向上传递,调用者需处理或继续传递。例如,函数A调用B,B抛出异常时,A的catch块处理。若A不处理,异常继续向上。实战中,声明noexcept标记函数不抛出异常,优化性能。案例:库函数声明noexcept,避免调用者额外开销。跨函数传递需明确职责边界。
#include <iostream>
void functionC() {
throw std::runtime_error("来自深层函数的异常");
}
void functionB() {
functionC(); // 不处理异常,继续向上传递
}
void functionA() {
try {
functionB();
} catch (const std::exception& e) {
std::cerr << "在functionA中捕获: " << e.what() << std::endl;
// 可以选择重新抛出
throw;
}
}
int main() {
try {
functionA();
} catch (const std::exception& e) {
std::cerr << "在main中最终处理: " << e.what() << std::endl;
}
return 0;
}
第六章:异常处理与多线程协同
多线程环境中,异常需在创建线程的上下文中处理。例如,std::thread的join()可能抛出异常,需在主线程catch块处理。实战中,避免线程间直接传递异常,改用std::promise或信号量同步。案例:生产者-消费者模型中,异常通过共享变量传递,确保线程安全。多线程异常处理需谨慎设计。
#include <iostream>
#include <thread>
#include <future>
#include <stdexcept>
int computeTask(int value) {
if (value < 0) {
throw std::invalid_argument("输入值不能为负");
}
return value * value;
}
int main() {
auto future = std::async(std::launch::async, computeTask, -5);
try {
int result = future.get();
std::cout << "计算结果: " << result << std::endl;
} catch (const std::exception& e) {
std::cerr << "线程异常: " << e.what() << std::endl;
}
return 0;
}
第七章:大型项目中的异常策略
大型项目需统一异常策略,如分层处理:底层函数抛出异常,高层捕获并转换。例如,数据库操作抛出DBError,业务层捕获后转为UserFriendlyError。实战中,定义异常基类BaseException,子类继承扩展。案例:微服务架构中,异常通过HTTP状态码传递,提升可维护性。统一策略减少耦合。
#include <iostream>
#include <string>
class BaseException : public std::exception {
protected:
std::string context;
public:
BaseException(const std::string& ctx) : context(ctx) {}
virtual std::string getContext() const { return context; }
};
class DBError : public BaseException {
public:
explicit DBError(const std::string& ctx) : BaseException(ctx) {}
const char* what() const noexcept override {
return "数据库操作异常";
}
};
class UserFriendlyError : public BaseException {
public:
explicit UserFriendlyError(const std::string& ctx) : BaseException(ctx) {}
const char* what() const noexcept override {
return "系统繁忙,请稍后重试";
}
};
void databaseOperation() {
throw DBError("连接数据库失败");
}
void businessLayer() {
try {
databaseOperation();
} catch (const DBError& e) {
throw UserFriendlyError(e.getContext());
}
}
int main() {
try {
businessLayer();
} catch (const UserFriendlyError& e) {
std::cerr << "用户友好提示: " << e.what() << std::endl;
}
return 0;
}
第八章:异常调试与性能优化
异常调试需结合日志和断点。例如,try块内记录关键状态,catch块输出错误上下文。性能优化方面,避免频繁抛出异常,改用错误码处理高频场景。案例:游戏引擎中,物理运算使用错误码,异常仅处理致命错误。调试工具如GDB可捕获异常栈,定位问题根源。
#include <iostream>
#include <chrono>
#include <stdexcept>
class PerformanceMonitor {
private:
std::chrono::steady_clock::time_point start;
public:
PerformanceMonitor() : start(std::chrono::steady_clock::now()) {}
~PerformanceMonitor() {
auto end = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "操作耗时: " << duration.count() << " 微秒" << std::endl;
}
};
// 高频操作使用错误码
bool fastOperation(int value, int& result) {
if (value < 0) return false; // 错误码方式
result = value * 2;
return true;
}
// 关键操作使用异常
void criticalOperation() {
PerformanceMonitor monitor;
throw std::runtime_error("关键业务异常");
}
int main() {
// 高频场景:错误码
int result;
if (!fastOperation(-5, result)) {
std::cerr << "操作失败" << std::endl;
}
// 关键场景:异常
try {
criticalOperation();
} catch (const std::exception& e) {
std::cerr << "关键异常: " << e.what() << std::endl;
}
return 0;
}
第九章:异常处理代码维护
良好异常设计有利于代码维护。例如,异常信息包含上下文(如文件名、行号),便于追踪。实战中,避免catch(…)捕获所有异常,明确类型处理。案例:日志系统中,异常按严重程度分类,便于后续分析。
#include <iostream>
#include <sstream>
#include <stdexcept>
class ContextualException : public std::exception {
private:
std::string file;
int line;
std::string message;
public:
ContextualException(const std::string& msg, const std::string& f, int l)
: message(msg), file(f), line(l) {}
const char* what() const noexcept override {
std::ostringstream oss;
oss << "在 " << file << ":" << line << " - " << message;
static std::string result = oss.str();
return result.c_str();
}
};
#define THROW_CONTEXTUAL(msg) \
throw ContextualException(msg, __FILE__, __LINE__)
void validateInput(int value) {
if (value > 100) {
THROW_CONTEXTUAL("输入值超过允许范围");
}
}
int main() {
try {
validateInput(150);
} catch (const ContextualException& e) {
std::cerr << "上下文异常: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cerr << "其他异常: " << e.what() << std::endl;
}
return 0;
}
第十章:实战案例综合演练
综合案例:实现一个文件解析器,处理CSV格式。自定义ParseError异常,try块读取文件,catch捕获std::ios_base::failure(文件不存在)和ParseError(格式错误)。资源管理使用std::unique_ptr,线程安全通过互斥锁保障。案例展示异常处理全流程,从设计到实现,巩固核心概念。
#include <iostream>
#include <fstream>
#include <sstream>
#include <memory>
#include <vector>
#include <stdexcept>
#include <mutex>
class ParseError : public std::exception {
private:
std::string message;
public:
explicit ParseError(const std::string& msg) : message(msg) {}
const char* what() const noexcept override {
return message.c_str();
}
};
class CSVParser {
private:
std::mutex mtx;
public:
std::vector<std::vector<std::string>> parseFile(const std::string& filename) {
std::lock_guard<std::mutex> lock(mtx);
std::ifstream file(filename);
if (!file.is_open()) {
throw std::ios_base::failure("无法打开文件: " + filename);
}
std::vector<std::vector<std::string>> data;
std::string line;
while (std::getline(file, line)) {
std::vector<std::string> row;
std::stringstream ss(line);
std::string cell;
while (std::getline(ss, cell, ',')) {
if (cell.empty()) {
throw ParseError("CSV格式错误: 空单元格");
}
row.push_back(cell);
}
if (row.empty()) {
throw ParseError("CSV格式错误: 空行");
}
data.push_back(row);
}
if (data.empty()) {
throw ParseError("CSV文件为空");
}
return data;
}
};
int main() {
CSVParser parser;
try {
auto data = parser.parseFile("data.csv");
std::cout << "成功解析 " << data.size() << " 行数据" << std::endl;
} catch (const std::ios_base::failure& e) {
std::cerr << "文件错误: " << e.what() << std::endl;
} catch (const ParseError& e) {
std::cerr << "解析错误: " << e.what() << std::endl;
} catch (const std::exception& e) {
std::cerr << "未知错误: " << e.what() << std::endl;
}
return 0;
}
QT原理与源码分析视频课程
QT QML C++高级扩展开发视频课程
QT QML应用程序性能优化实战视频课程
QT应用程序性能优化实战视频课程
QT&QML原理源码界面美化网络编程(QT5视频课程)
QT&QML性能优化网络编程界面美化(QT6视频课程)
QT C++网络编程系列视频课程
QT+OpenCV+开源框架计算机视觉技术项目实战
如果您认为这篇博客对您有所帮助,请您一定立即点赞+喜欢+收藏,作者将能从您的点赞+喜欢+收藏中获取到创作新的好博客的动力。如果您认为作者写的博客对您有一点帮助,您也可以关注这篇博客的作者。
更多推荐

所有评论(0)