C++异常是一种处理程序运行时错误的机制,它允许程序在检测到错误时跳转到预定义的错误处理代码,而不必通过函数返回值层层传递错误信息。
异常的基本概念
- 异常抛出(throw):当程序检测到错误时,使用
throw关键字抛出一个异常对象 - 异常捕获(catch):使用
try-catch块捕获并处理抛出的异常 - 异常传播:如果当前函数不能处理异常,异常会沿着函数调用栈向上传播,直到找到合适的处理代码
异常处理的基本语法
try {
// 可能抛出异常的代码
if (error_condition) {
throw exception_object; // 抛出异常
}
}
catch (exception_type1 e) {
// 处理type1类型的异常
}
catch (exception_type2 e) {
// 处理type2类型的异常
}
catch (...) {
// 处理所有其他类型的异常(通配符)
}
异常类型
C++允许抛出任何类型的异常,包括:
基本数据类型:如
int、char等throw 404; // 抛出整数异常 throw "Not found"; // 抛出字符串字面量异常自定义类型:通常是类或结构体
class MyException { private: string message; public: MyException(string msg) : message(msg) { } string getMessage() const { return message; } }; // 抛出自定义异常 throw MyException("发生了错误");标准库异常:C++标准库提供了一系列异常类,定义在
<exception>头文件中,主要包括:std::exception:所有标准异常的基类std::runtime_error:运行时错误std::logic_error:逻辑错误std::out_of_range:超出范围错误(如数组越界)std::invalid_argument:无效参数错误
异常规范(C++11前)
早期C++允许使用异常规范指定函数可能抛出的异常类型:
// 声明该函数可能抛出int或string类型的异常
void func() throw(int, string) {
// ...
}
// 声明该函数不抛出任何异常
void func() throw() {
// ...
}
C++11引入了noexcept关键字替代异常规范:
// 声明该函数不会抛出任何异常
void func() noexcept {
// ...
}
// 条件性noexcept
void func() noexcept(condition) {
// ...
}
异常处理的最佳实践
- 只在异常情况下使用异常:不要将异常用于常规控制流
- 捕获适当的异常类型:避免过度使用
catch(...) - 按引用捕获异常:避免异常对象的复制,同时允许捕获派生类异常
catch (const MyException& e) { // 推荐使用const引用 // ... } - 清理资源:使用RAII(资源获取即初始化)技术确保资源正确释放
- 异常安全:设计函数时考虑异常发生时的状态一致性
异常的优缺点
优点:
- 分离正常代码和错误处理代码,提高可读性
- 可以在调用链的任意层次处理异常,不必每层都检查错误
- 能够传递更丰富的错误信息
缺点:
- 可能影响性能(异常处理代码通常不被编译器优化)
- 过度使用会使程序逻辑变得复杂
- 可能导致资源泄露(如果没有正确处理)
示例:完整的异常处理程序
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
// 除法函数,当除数为0时抛出异常
double divide(double num, double den) {
if (den == 0) {
throw invalid_argument("除数不能为0");
}
return num / den;
}
int main() {
try {
double result = divide(10, 0);
cout << "结果: " << result << endl;
}
catch (const invalid_argument& e) {
cerr << "错误: " << e.what() << endl;
}
catch (...) {
cerr << "发生了未知错误" << endl;
}
return 0;
}
这个例子中,divide函数在检测到除数为0时抛出invalid_argument异常,main函数中的try-catch块捕获并处理这个异常,确保程序能够优雅地处理错误情况。