std::get 失败时抛 std::bad_variant_access 异常;应先用 std::holds_alternative 或 std::get_if 安全检查,优先使用 std::visit 避免异常;警惕 valueless_by_exception 状态导致未定义行为。

std::get 失败时抛 std::bad_variant_access 异常
运行时调用 std::get<t>(v)</t> 但 v 当前不持有 T 类型,会立即抛出 std::bad_variant_access ——不是编译错误,而是未捕获就直接 std::terminate。常见于解析配置、处理异构日志字段等场景,一访问错类型就崩。
- 它不关心你“以为”存的是什么,只认当前
v.index()对应的活跃类型 - 即使
T在std::variant模板参数列表中,只要此刻没被构造/赋值,std::get就会失败 - 注意:若
v处于valueless_by_exception状态(比如移动std::string时内存分配失败),连std::holds_alternative和v.index()都是未定义行为,不能调
安全检查必须分两层:先判状态,再取值
别依赖注释或外部逻辑“保证类型”,C++ 不做运行时宽容。正确路径是:先确认是否可能持有该类型,再尝试提取。
- 用
std::holds_alternative<t>(v)</t>判断当前是否为T—— 返回bool,安全,不抛异常 - 更推荐
std::get_if<t>(&v)</t>:返回T*,空指针表示不匹配,无需try/catch,也避开valueless_by_exception的雷区 - 示例:
if (auto* s = std::get_if<std::string>(&v)) { std::cout << *s << "\n"; } else if (auto* i = std::get_if<int>(&v)) { std::cout << *i << "\n"; }
std::visit 是默认安全访问方式,别绕开它
除非业务强约束必须拿到引用/指针(如传给旧接口),否则所有访问都该走 std::visit。它天然覆盖所有备选类型,编译期强制穷举,不漏分支也不抛异常。
- 泛型 lambda 最简:
std::visit([](auto&& x) { /* 通用处理 */ }, v); - 差异化处理用
std::overload组合多个 lambda,漏一个类型编译就报错 - 需要状态或复用逻辑?写显式访问者类,重载每个
operator()(const T&),少一个就编译失败
容易忽略的 valueless_by_exception 状态
这是最隐蔽的地雷:一旦某个替代类型(如 std::string)在移动构造/赋值时抛异常,v 进入 valueless_by_exception,此时任何访问操作(包括 std::holds_alternative、std::get_if、v.index())都是未定义行为。
立即学习“C++免费学习笔记(深入)”;
- 无法通过常规手段检测该状态,标准库没提供
has_value()类接口 - 唯一缓解方式:避免在
std::variant中放入可能抛异常的移动操作类型;或确保所有构造/赋值都在try块内,出异常后不再访问该实例 - 如果必须高可靠性,考虑用
std::monostate占位并前置,至少让默认构造和清空有明确定义


















