std::variant 解决传统 union 类型不安全问题,通过内置类型标签实现安全访问;支持 std::get、std::get_if、std::holds_alternative 安全读写,并借助 std::visit 实现类型匹配分发。

std::variant 能解决什么问题
传统 union 允许在一块内存里存不同类型的值,但不记录当前实际存的是哪种类型,访问错误类型会直接导致未定义行为。比如你写了 union { int i; double d; },然后往里面写了 i = 42,却读 d,程序就崩了——编译器不管,运行时也不报错,只等出事。
std::variant 把类型信息“带在身上”,每次赋值或修改都会更新内部的类型标签,读取前还能用 std::holds_alternative 或 std::get_if 安全检查,从根本上堵住误读漏洞。
怎么安全地读写 std::variant 的值
不能像 union 那样直接点成员或强制转型。必须通过标准接口操作,否则编译失败(这是好事)。
- 写入:直接赋值,例如
v = 42、v = 3.14、v = std::string{"hello"},v会自动切换到对应类型 - 读取单个类型:用
std::get<t>(v)</t>—— 如果当前不是T类型,抛std::bad_variant_access - 安全读取:先用
std::get_if<t>(&v)</t>拿指针,返回nullptr表示当前不是T,否则解引用访问 - 类型判断:用
std::holds_alternative<int>(v)</int>得到bool
std::variant<int std::string> v = "abc";
if (std::holds_alternative<:string>(v)) {
std::cout (v); // ok
} else {
std::cout (v); // 不会执行
}</:string></int>
std::visit 是怎么配合 variant 一起用的
当你要对多种可能类型做不同处理(比如打印、序列化、计算),逐个 if/else + holds_alternative 写起来啰嗦还容易漏分支。std::visit 提供了一种类型安全的“分发”机制,它会在运行时根据 variant 当前实际类型,自动调用匹配的重载函数。
- 参数必须是可调用对象(lambda、函数对象、普通函数),且每个重载都得覆盖
variant所有可选项 - 如果漏掉某个类型,编译失败,而不是运行时报错
- 支持多个
variant同时 visit(C++17 起),适合组合场景
std::variant<int double std::string> v = 3.14;
std::visit([](const auto& x) {
using T = std::decay_t<decltype>;
if constexpr (std::is_same_v<t int>) {
std::cout ) {
std::cout ) {
std::cout
<h3>要注意的边界和开销</h3>
<p><code>std::variant</code> 不是零成本抽象。它比裸 <code>union</code> 多占至少一个<a style="color:#f60; text-decoration:underline;" title="字节" href="https://m.php.cn/zt/16298.html" target="_blank">字节</a>(用于存储类型索引),而且构造/赋值/析构都涉及分支判断和可能的内存操作。</p>
<ul>
<li>如果所有备选类型都是 trivial(如 <code>int</code>、<code>float</code>),<code>variant</code> 本身也是 trivial 的;但只要有一个非 trivial 类型(比如 <code>std::string</code>),它就会带上默认构造、析构等逻辑</li>
<li>不能存引用、数组、<code>void</code>、抽象类等无法实例化的类型</li>
<li>不能包含自身(<code>std::variant<int std::variant>></int></code> 不合法),需要用 <code>std::unique_ptr</code> 或间接方式绕过</li>
<li>移动语义正常工作,但注意某些类型(如 <code>std::string</code>)移动后状态不确定,别在 <code>visit</code> 里反复用同一个变量多次访问</li>
</ul>
<p>真正关键的是:别把它当成“万能容器”滥用。如果类型组合固定、逻辑清晰,<code>variant</code> 是极好的选择;但如果类型太多、嵌套太深、或者需要动态增删类型,该用多态或其它设计模式就别硬扛。</p></t></decltype></int>C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!









