目录
C++ throw
详解:异常处理的核心机制
一、异常处理的基本概念
C++ 中的 throw
是异常处理的核心关键字,用于主动触发异常。异常机制允许程序在检测到错误时,跳出当前执行流程,将控制权交给异常处理器(try-catch
块),从而实现错误的分层管理。
二、throw
的作用与语法
1. 核心作用
- 错误传递:将错误信息从底层传递到上层调用栈。
- 流程控制:中断当前函数,寻找匹配的
catch
块。 - 资源释放:通过栈展开(Stack Unwinding)确保局部对象析构。
2. 语法格式
throw expression; // 抛出一个异常对象(任意类型)
三、基础用法示例
1. 抛出内置类型异常
#include <iostream>
using namespace std;
double divide(int a, int b) {
if (b == 0) {
throw "Division by zero!"; // 抛出const char*类型异常
}
return static_cast<double>(a) / b;
}
int main() {
try {
cout << divide(10, 0) << endl;
} catch (const char* msg) { // 捕获异常
cerr << "Error: " << msg << endl;
}
return 0;
}
// 输出:Error: Division by zero!
2. 抛出标准库异常
C++ 标准库提供了 <stdexcept>
中预定义的异常类(如 runtime_error
),更推荐使用:
#include <stdexcept>
double divide(int a, int b) {
if (b == 0) {
throw std::runtime_error("Division by zero!");
}
return static_cast<double>(a) / b;
}
int main() {
try {
divide(10, 0);
} catch (const std::runtime_error& e) {
cerr << "Error: " << e.what() << endl;
}
return 0;
}
四、自定义异常类
通过继承 std::exception
实现自定义异常,增强可维护性:
#include <exception>
#include <string>
class MyException : public std::exception {
private:
std::string message;
public:
MyException(const std::string& msg) : message(msg) {}
const char* what() const noexcept override {
return message.c_str();
}
};
void validate(int value) {
if (value < 0) {
throw MyException("Value cannot be negative!");
}
}
int main() {
try {
validate(-5);
} catch (const MyException& e) {
cerr << "Custom Error: " << e.what() << endl;
}
return 0;
}
// 输出:Custom Error: Value cannot be negative!
五、throw
的高级特性
1. 异常规格(C++17 前)与 noexcept
(C++11+)
- 废弃的异常规格(C++17 前):
void func() throw(std::runtime_error); // 声明可能抛出std::runtime_error
- 现代替代
noexcept
:void safe_func() noexcept; // 承诺不抛出任何异常
2. 重新抛出异常
在 catch
块中捕获后再次抛出,允许上层处理:
try {
// 可能抛出异常的代码
} catch (const std::exception& e) {
cerr << "Log: " << e.what() << endl;
throw; // 重新抛出当前异常
}
六、异常安全与最佳实践
-
RAII 原则:使用智能指针、容器等管理资源,确保异常发生时资源自动释放。
void processFile() { std::ifstream file("data.txt"); if (!file) throw std::runtime_error("File open failed"); // 文件操作(若异常抛出,file析构会自动关闭句柄) }
-
避免在析构函数中抛出异常:可能导致程序终止(C++默认行为)。
-
优先使用标准异常类型:如
invalid_argument
、out_of_range
等,保持代码一致性。 -
明确异常层次:自定义异常继承自
std::exception
,便于统一捕获。
七、综合案例:安全动态数组
结合模板类与异常处理,实现一个类型安全的动态数组:
#include <iostream>
#include <stdexcept>
template <typename T>
class SafeArray {
private:
T* data;
size_t size;
public:
SafeArray(size_t n) : size(n), data(new T[n]) {}
~SafeArray() { delete[] data; }
T& operator[](size_t index) {
if (index >= size) {
throw std::out_of_range("Index out of bounds");
}
return data[index];
}
size_t getSize() const { return size; }
};
int main() {
try {
SafeArray<int> arr(5);
arr[0] = 10;
arr[5] = 20; // 触发越界异常
} catch (const std::exception& e) {
std::cerr << "Exception caught: " << e.what() << std::endl;
}
return 0;
}
// 输出:Exception caught: Index out of bounds
八、总结
- 核心作用:
throw
提供了一种结构化的错误处理机制。 - 适用场景:函数遇到无法处理的错误时(如无效参数、资源不足)。
- 关键原则:
- 异常应用于“异常情况”,而非普通控制流。
- 结合 RAII 保证资源安全。
- 优先使用标准异常或自定义层次化的异常类。
通过合理使用 throw
和 try-catch
,可以显著提升代码的健壮性和可维护性。
研究学习不易,点赞易。
工作生活不易,收藏易,点收藏不迷茫 :)