typeid(*p) 解引用空指针且p为多态类型时必抛std::bad_typeid,必须先判空;非多态类型解引用空指针是未定义行为;禁用RTTI时该异常不会抛出,但行为未定义。

typeid(*p) 遇到空指针直接崩溃?必须先判空
只要 typeid 的实参是解引用空指针(如 *p),且 p 指向多态类型,就一定会抛出 std::bad_typeid。这不是可选行为,是标准强制要求——没得商量,不判空就是 crash。
防御方式极其简单:在调用 typeid(*p) 前,必须显式检查指针非空。
- 对指针使用
if (p != nullptr)或if (p)判空,再进typeid - 不要依赖
try/catch包裹typeid来“兜底”——异常路径本就不该是常规流程 - 若逻辑上允许空值,优先考虑用
std::optional<T&>或返回std::type_info const*的封装函数,避免裸指针解引用
为什么只对多态类型才抛 bad_typeid?非多态类不会触发
typeid 对非多态类型(即没有虚函数的类)做静态类型推导,不查虚表,因此即使解引用空指针也不会触发运行时检查——但这不是安全,是未定义行为(UB)。编译器可能优化掉整个分支,也可能当场段错误。
真正受 std::bad_typeid 约束的,仅限于满足两个条件的表达式:多态类型 + 解引用空指针。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 多态类型:类中至少有一个虚函数(包括虚析构函数)
- 空指针:
p == nullptr,且你写了typeid(*p) - 注意:
typeid(p)(指针本身)永远安全,它只返回指针类型的type_info
想统一处理类型查询?别硬扛 typeid,改用 dynamic_cast + 类型 ID
如果目标是“安全获取对象实际类型”,typeid 本身设计就带风险。更健壮的做法是结合 dynamic_cast 和已知类型集合做判断:
- 用
dynamic_cast<Derived*>(base_ptr)替代typeid(*base_ptr) == typeid(Derived) - 成功返回非空指针,失败返回
nullptr—— 可预测、无异常、零开销失败路径 - 若需枚举所有可能子类,可维护一个
std::type_info const*查表,但表项必须来自typeid(Derived).hash_code()这类稳定标识,而非不可靠的name()
这比反复 try/catch bad_typeid 更轻量,也更符合 C++ 的零成本抽象原则。
RTTI 关闭时 typeid 行为会变,但 bad_typeid 不会出现
如果编译时加了 -fno-rtti(GCC/Clang)或 /GR-(MSVC),<typeinfo></typeinfo> 头文件仍可用,但 typeid 对多态类型的求值结果是未定义的——bad_typeid 不会抛出,因为 RTTI 根本没启用。
此时代码可能静默返回错误类型,或在某些平台直接崩溃。所以:
- 项目若禁用 RTTI,就彻底别碰
typeid(*p)和dynamic_cast - 用
static_cast或模板std::is_same_v替代编译期已知的类型判断 - 运行时类型识别需求强烈?那 RTTI 就不该关——关了还指望
bad_typeid提醒你,纯属缘木求鱼
真正容易被忽略的是:bad_typeid 不是“提醒你错了”的友好异常,它是 RTTI 正常工作时的最后一道防线;一旦你开始靠 catch 它来让程序不死,说明类型检查逻辑已经失控了。

















