std::variant 安全替代裸 union:自带类型信息、自动调用构造/析构函数、访问时类型不匹配抛 std::bad_variant_access 异常,避免未定义行为。

在 C++ 中直接使用 union 是危险的:它不跟踪当前存储的类型,不自动调用构造/析构函数,容易引发未定义行为(UB)。C++17 引入的 std::variant 正是为安全替代裸 union 而设计——它自带类型信息、自动管理生命周期、提供访问保护。
裸 union 的主要风险
传统 union 仅共享内存,不记录哪个成员被初始化:
- 读取未激活的成员 → 未定义行为(如读
str但刚写了i) - 含非平凡类型(如
std::string)时,手动管理构造/析构极易出错 - 无编译期或运行期类型检查,错误常在运行时才暴露
std::variant 如何解决这些问题
std::variant 是类型安全的“可变容器”,内部维护当前索引和活跃值:
- 构造时自动调用对应类型的构造函数(支持移动、拷贝、带参构造)
- 赋值或销毁时自动调用旧值的析构函数、新值的构造函数
- 通过
std::get或(v) std::visit访问,若类型不匹配则抛std::bad_variant_access - 支持
std::holds_alternative运行时类型查询(v)
安全迁移示例:从 union 到 variant
假设原意表示“整数或字符串”:
立即学习“C++免费学习笔记(深入)”;
// ❌ 危险的 union(尤其含 std::string)
union BadValue {
int i;
std::string s; // 非平凡类型 —— 构造/析构必须手动处理!
};
BadValue v;
new(&v.s) std::string("hello"); // 手动构造
v.s.~basic_string(); // 必须手动析构 —— 漏掉就泄漏
✅ 安全等价写法:
#include#include using Value = std::variant Value v = 42; // 自动调用 int 构造 v = std::string{"hi"}; // 自动析构 int、构造 string std::visit([](const auto& x) { using T = std::decay_t ; if constexpr (std::is_same_v ) std::cout << "int: " << x; else if constexpr (std::is_same_v ) std::cout << "string: " << x; }, v);











