std::rethrow_exception仅用于跨线程或作用域传递异常,须配合std::current_exception()和std::exception_ptr;catch中重抛应使用throw;而非std::rethrow_exception。

直接说结论: std::rethrow_exception 不是用来“重新抛出当前异常”的,它只能配合 std::current_exception() 和 std::exception_ptr 在**不同线程或作用域间传递异常对象**;想在 catch 块里原样重抛当前异常,应该用 throw;(空 throw),不是 std::rethrow_exception。
什么时候必须用 std::rethrow_exception
典型场景是:你在某个线程捕获了异常,但不想立刻处理,而是把异常“打包”保存下来,等主线程或其他上下文再统一处理。这时你不能直接保存 std::exception&(栈已销毁),也不能直接 throw(跨线程非法),必须走 std::exception_ptr 这条路。
-
std::current_exception()获取当前异常的拷贝,返回std::exception_ptr -
std::rethrow_exception(ptr)在任意位置把该 ptr 对应的异常对象重新抛出(会触发栈展开) - 同一个
std::exception_ptr可被多次rethrow_exception,每次都是新抛出(不是“转发”,是复制后抛)
void worker_thread() {
try {
risky_operation();
} catch (...) {
// 保存异常,不立即处理
g_exc_ptr = std::current_exception(); // 全局或传给主线程
}
}
// 主线程中
if (g_exc_ptr) {
std::rethrow_exception(g_exc_ptr); // 此处才真正抛出
}
throw; 和 std::rethrow_exception(std::current_exception()) 的区别
这是最容易混淆的点:两者行为表面相似,但底层机制和开销完全不同。
-
throw;是语言内置语法,**零拷贝、无类型擦除、保持原始异常对象身份**,性能最优,且能被catch(...)精准捕获 -
std::rethrow_exception(std::current_exception())会强制做一次异常对象深拷贝 + 类型擦除 → 包装成std::exception_ptr→ 再解包抛出,**额外开销大,还可能丢失某些自定义异常的非常量成员状态** - 更关键的是:
throw;只能在 active exception context(即正在处理一个异常的 catch 块内)使用;而std::rethrow_exception可以在任何地方调用(只要 ptr 非空)
常见误用与崩溃原因
下面这些写法要么编译不过,要么运行时崩,务必避开:
Python v2.4版chm格式的中文手册,内容丰富全面,不但是一本手册,你完全可以把她作为一本Python的入门教程,教你如何使用Python解释器、流程控制、数据结构、模板、输入和输出、错误和异常、类和标准库详解等方面的知识技巧。同时后附的手册可以方便你的查询。
立即学习“C++免费学习笔记(深入)”;
- 在没有活跃异常时调用
std::current_exception()→ 返回空std::exception_ptr,后续std::rethrow_exception(nullptr)会直接调用std::terminate() - 把
std::exception_ptr存到局部变量,然后函数返回后再用 → 指向的异常对象可能已被析构(实际由exception_ptr自动管理生命周期,但若 ptr 被提前重置或离开作用域,行为未定义) - 试图用
std::rethrow_exception替代throw e;(带对象的 throw)→ 这会切掉异常对象的派生关系,catch(const MyException&)可能捕不到 - 多线程共享
std::exception_ptr但没加锁 →exception_ptr本身是线程安全的(引用计数原子),但读写共享变量仍需同步
最常被忽略的一点:异常对象的生命期由 std::exception_ptr 的引用计数控制,不是由原始 throw 行为决定。如果你在 catch 块里只调用了 std::current_exception() 却没保存返回值,那个异常对象会在 catch 块结束时被销毁 —— 此时再拿别的 ptr 去 rethrow,可能已经无效。










