You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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被禁用,常规的类型捕获逻辑无法识别它。

解决方法

  1. 启用RTTI:如果项目允许,移除编译选项中的-fno-rtti,异常类型匹配就能正常工作。
  2. 改用错误码处理:如果必须禁用RTTI,可以放弃标准库的异常抛出逻辑,转而使用错误码(比如std::optional、自定义错误枚举)处理解析失败。例如用std::from_chars代替std::stod,它不会抛出异常,而是返回错误状态。

内容的提问来源于stack exchange,提问作者Alexander Gruzintsev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 15:41:12