不使用std::current_exception检测是否处于catch块的方法
std::current_exception的情况下检测活跃异常 首先得明确:C++标准库中没有提供完全可移植、且无堆分配开销的方式来直接检测当前是否存在活跃异常。不过,如果你能接受依赖编译器特定扩展,或者愿意重新评估std::current_exception()的实际开销,还是有几种方案能解决你的问题。
先澄清一个误解:std::current_exception()的开销其实没你想的大
你担心调用std::current_exception()会触发堆分配和异常复制,但实际上:
- 当没有活跃异常时,它只是返回一个空的
std::exception_ptr,这个操作几乎没有开销(不会涉及堆分配); - 只有当存在活跃异常时,它才会复制异常对象产生开销——但此时你本来就要处理异常,这点开销通常是可接受的。
如果可以接受这个极小的开销,最稳妥的标准方案是直接用它来检测:
#include <iostream> #include <exception> const char *what() { // 无活跃异常时直接返回nullptr,无额外开销 if (!std::current_exception()) { return nullptr; } try { throw; } catch (int) { return "int"; } catch (const char *e) { return e; } catch (const std::exception &e) { return e.what(); } catch (...) { // 兜底处理未知异常类型,避免程序终止 return "unknown exception"; } } int main() { try { throw "hello"; } catch (...) { std::cerr << "calling what with active exception" << std::endl; if (const char* msg = what()) std::cerr << msg << std::endl; } std::cerr << "calling what without active exception" << std::endl; if (const char* msg = what()) std::cerr << msg << std::endl; else std::cerr << "nullptr returned" << std::endl; }
追求极致性能:编译器特定扩展方案
如果你完全不想碰std::current_exception(),可以用编译器提供的ABI扩展函数,这些函数直接查询异常处理状态,无任何堆开销。
GCC/Clang 环境
GCC和Clang支持__cxa_in_exception()函数(来自C++ ABI),它直接返回bool值,告诉你当前是否处于异常处理流程中(包括catch块内或异常传播过程中):
#include <iostream> #include <exception> // 声明编译器扩展函数 extern "C" bool __cxa_in_exception(); const char *what() { if (!__cxa_in_exception()) { return nullptr; } try { throw; } catch (int) { return "int"; } catch (const char *e) { return e; } catch (const std::exception &e) { return e.what(); } catch (...) { return "unknown exception"; } }
MSVC 环境
MSVC没有直接对应__cxa_in_exception()的函数,但可以用__uncaught_exceptions()(C++17标准引入,MSVC完全支持)辅助判断。不过要注意:__uncaught_exceptions()返回的是当前未被捕获的异常数量——在catch块内时,这个值会减1(因为当前异常已被捕获),所以需要结合调用场景判断。如果只是想避免throw;导致的终止,也可以直接用std::current_exception()(MSVC中无活跃异常时同样无堆分配)。
最后一个提醒
不管用哪种方案,一定要加上catch(...)兜底,否则如果活跃异常不属于你预设的捕获类型,throw;会直接触发std::terminate(),导致程序终止。
内容的提问来源于stack exchange,提问作者anton_rh

