异常处理
C++ 异常处理是通过 try、catch 和 throw 关键字来实现的,主要用于在程序运行过程中出现错误时进行错误捕获与处理,从而提高程序的健壮性和可维护性。
一、基本语法结构
try {
// 可能抛出异常的代码
throw 异常对象;
}
catch (异常类型1 参数名) {
// 对异常类型1的处理
}
catch (异常类型2 参数名) {
// 对异常类型2的处理
}
// ...
catch (...) {
// 捕获所有类型的异常(兜底处理)
}
二、示例
#include <iostream>
using namespace std;
int divide(int a, int b) {
if (b == 0)
throw runtime_error("除数不能为0"); // 抛出异常
return a / b;
}
int main() {
try {
int result = divide(10, 0);
cout << "结果是: " << result << endl;
}
catch (const runtime_error& e) {
cout << "发生异常: " << e.what() << endl;
}
catch (...) {
cout << "发生了未知异常" << endl;
}
return 0;
}
输出:
发生异常: 除数不能为0
三、异常类型
- 基本类型:如
int,const char*(不推荐) - STL 标准异常类(推荐):
std::exception:所有标准异常的基类std::runtime_error:运行时错误std::logic_error:逻辑错误std::out_of_range,std::invalid_argument等更具体的派生类
四、自定义异常类
你可以自定义异常类并继承自 std::exception:
class MyException : public std::exception {
public:
const char* what() const noexcept override {
return "这是一个自定义异常";
}
};
五、注意事项
- 异常是运行时处理机制,不影响编译过程。
- 不要滥用异常,在性能敏感的代码中尽量使用错误码。
- 析构函数应为
noexcept(否则在异常传播时若析构再抛异常,程序将调用std::terminate())。 throw;可以在catch中重新抛出当前异常。- 异常处理机制的开销存在,但在正确使用时能显著提高代码可读性与鲁棒性。
六、C++11/14/17 中对异常处理的增强
C++11 和 C++17 对异常处理机制进行了增强和优化,主要包括更严格的异常安全规范、更丰富的异常传递工具,以及性能上的改进。下面逐一介绍重点特性:
1. noexcept 关键字(替代 throw())
用法:
void f() noexcept; // 保证不抛出异常
void g() noexcept(true); // 同上
void h() noexcept(false); // 可能抛出异常(等同于无 noexcept)
编译器行为:
- 如果函数标记为
noexcept,但在运行中抛出了异常,则程序会调用std::terminate()。 - 编译器可基于
noexcept优化函数的调用,例如移动构造(std::vector仅在元素移动构造是noexcept时才优先使用move)。
示例:
void may_throw();
void safe_func() noexcept {
// may_throw(); // ❌ 如果调用了可能抛异常的函数,这里编译报错
}
2. noexcept 运算符
可以用来在编译期判断一个表达式是否 noexcept:
template <typename T>
void func(T&& x) noexcept(noexcept(T(std::move(x)))) {
// ...
}
3. std::nested_exception / std::throw_with_nested
用于嵌套异常信息,使异常链条更清晰(类似 Java 的异常链)。
示例:
#include <iostream>
#include <exception>
#include <stdexcept>
void lowLevel() {
throw std::runtime_error("low-level error");
}
void highLevel() {
try {
lowLevel();
} catch (...) {
std::throw_with_nested(std::runtime_error("high-level context"));
}
}
void print_exception(const std::exception& e, int level = 0) {
std::cerr << std::string(level * 2, ' ') << "Exception: " << e.what() << '\n';
try {
std::rethrow_if_nested(e);
} catch (const std::exception& nested) {
print_exception(nested, level + 1);
} catch (...) {}
}
int main() {
try {
highLevel();
} catch (const std::exception& e) {
print_exception(e);
}
}
输出:
Exception: high-level context
Exception: low-level error
4. C++17: std::uncaught_exceptions()
取代 C++98 的 std::uncaught_exception()(注意多了个 s),可以判断当前栈上有多少个未处理的异常。
用于实现 RAII + 异常安全
struct Transaction {
int old_uncaught = std::uncaught_exceptions();
~Transaction() {
if (std::uncaught_exceptions() > old_uncaught) {
std::cout << "Rollback!\n";
} else {
std::cout << "Commit!\n";
}
}
};
⚠ 注意事项
noexcept函数不能抛异常,否则程序终止,建议仅在能保证不抛异常的函数上使用。- 异常嵌套机制不影响原有
catch捕获链,但可以辅助追踪复杂异常因果关系。 std::uncaught_exceptions()是实现事务和资源回滚模式的重要工具。
未经作者同意请勿转载
本文来自博客园作者:aixueforever,原文链接:https://www.cnblogs.com/aslanvon/p/18938792

浙公网安备 33010602011771号