macOS M1禁用RTTI时,std::invalid_argument无法被捕获的原因?
C++禁用RTTI后异常捕获失效问题
我在C++异常捕获时遇到了一个奇怪的问题:代码逻辑上应该捕获std::invalid_argument异常,但实际却走到了catch (...)块里,希望有人能帮忙分析原因。
代码片段
#include <iostream> #include <string> #include <exception> int main() { try { std::stod("notanumber"); } catch (const std::invalid_argument&) { std::cerr << "std::invalid_argument" << std::endl; } catch (const std::out_of_range&) { std::cerr << "std::out_of_range" << std::endl; } catch (const std::exception&) { std::cerr << "Caught by ancestor" << std::endl; } catch (...) { auto ptr = std::current_exception(); auto type = __cxxabiv1::__cxa_current_exception_type(); std::cerr << type->name() << std::endl; std::cerr << "..." << std::endl; } return 0; }
程序输出
St16invalid_argument ...
环境详情
- C++14标准
- 禁用RTTI(Run-Time Type Information)
- Clang 13.1.6 arm64-apple-darwin-21.6.0
- macOS Monterey 12.6
我原本预期异常会被第一个catch (const std::invalid_argument&)块捕获,但实际并没有。
更新:最简捕获逻辑同样失效
即使简化成下面的代码,std::invalid_argument依然无法被捕获:
try { std::stod("notanumber"); } catch (const std::invalid_argument&) { // 未捕获到异常 std::cerr << "std::invalid_argument" << std::endl; }
问题原因
这是因为禁用RTTI后,C++的异常类型匹配机制无法正常工作。
C++中,通过类型匹配捕获异常(比如catch (const std::invalid_argument&))依赖RTTI来识别抛出的异常实际类型,进而匹配对应的catch块。当你禁用RTTI(通常通过编译选项-fno-rtti)后,编译器无法在运行时获取异常的类型信息,也就无法完成基于类型的匹配,最终所有类型化的catch块都会失效,异常只能被catch (...)捕获。
另外,你在catch (...)里通过__cxxabiv1::__cxa_current_exception_type()获取到的类型名St16invalid_argument是编译器内部的名称修饰后的结果,对应std::invalid_argument,这说明异常确实是这个类型,但因为RTTI被禁用,常规的类型捕获逻辑无法识别它。
解决方法
- 启用RTTI:如果项目允许,移除编译选项中的
-fno-rtti,异常类型匹配就能正常工作。 - 改用错误码处理:如果必须禁用RTTI,可以放弃标准库的异常抛出逻辑,转而使用错误码(比如
std::optional、自定义错误枚举)处理解析失败。例如用std::from_chars代替std::stod,它不会抛出异常,而是返回错误状态。
内容的提问来源于stack exchange,提问作者Alexander Gruzintsev
相关产品推荐
相关产品推荐

