0

0

C++中的std::variant有什么作用?(类型安全的联合体union替代品)

尼克

尼克

发布时间:2026-01-11 11:13:40

|

190人浏览过

|

来源于php中文网

原创

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

c++中的std::variant有什么作用?(类型安全的联合体union替代品)

std::variant 能解决什么问题

传统 union 允许在一块内存里存不同类型的值,但不记录当前实际存的是哪种类型,访问错误类型会直接导致未定义行为。比如你写了 union { int i; double d; },然后往里面写了 i = 42,却读 d,程序就崩了——编译器不管,运行时也不报错,只等出事。

std::variant 把类型信息“带在身上”,每次赋值或修改都会更新内部的类型标签,读取前还能用 std::holds_alternativestd::get_if 安全检查,从根本上堵住误读漏洞。

怎么安全地读写 std::variant 的值

不能像 union 那样直接点成员或强制转型。必须通过标准接口操作,否则编译失败(这是好事)。

  • 写入:直接赋值,例如 v = 42v = 3.14v = std::string{"hello"}v 会自动切换到对应类型
  • 读取单个类型:用 std::get(v) —— 如果当前不是 T 类型,抛 std::bad_variant_access
  • 安全读取:先用 std::get_if(&v) 拿指针,返回 nullptr 表示当前不是 T,否则解引用访问
  • 类型判断:用 std::holds_alternative(v) 得到 bool
std::variant v = "abc";
if (std::holds_alternative(v)) {
    std::cout << std::get(v); // ok
} else {
    std::cout << std::get(v); // 不会执行
}

std::visit 是怎么配合 variant 一起用的

当你要对多种可能类型做不同处理(比如打印、序列化、计算),逐个 if/else + holds_alternative 写起来啰嗦还容易漏分支。std::visit 提供了一种类型安全的“分发”机制,它会在运行时根据 variant 当前实际类型,自动调用匹配的重载函数。

无阶未来模型擂台/AI 应用平台
无阶未来模型擂台/AI 应用平台

无阶未来模型擂台/AI 应用平台,一站式模型+应用平台

下载

立即学习C++免费学习笔记(深入)”;

  • 参数必须是可调用对象(lambda、函数对象、普通函数),且每个重载都得覆盖 variant 所有可选项
  • 如果漏掉某个类型,编译失败,而不是运行时报错
  • 支持多个 variant 同时 visit(C++17 起),适合组合场景
std::variant v = 3.14;
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 << "double: " << x;
    } else if constexpr (std::is_same_v) {
        std::cout << "string: " << x;
    }
}, v);

要注意的边界和开销

std::variant 不是零成本抽象。它比裸 union 多占至少一个字节(用于存储类型索引),而且构造/赋值/析构都涉及分支判断和可能的内存操作。

  • 如果所有备选类型都是 trivial(如 intfloat),variant 本身也是 trivial 的;但只要有一个非 trivial 类型(比如 std::string),它就会带上默认构造、析构等逻辑
  • 不能存引用、数组、void、抽象类等无法实例化的类型
  • 不能包含自身(std::variant> 不合法),需要用 std::unique_ptr 或间接方式绕过
  • 移动语义正常工作,但注意某些类型(如 std::string)移动后状态不确定,别在 visit 里反复用同一个变量多次访问

真正关键的是:别把它当成“万能容器”滥用。如果类型组合固定、逻辑清晰,variant 是极好的选择;但如果类型太多、嵌套太深、或者需要动态增删类型,该用多态或其它设计模式就别硬扛。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

315

2023.08.02

css中float用法
css中float用法

css中float属性允许元素脱离文档流并沿其父元素边缘排列,用于创建并排列、对齐文本图像、浮动菜单边栏和重叠元素。想了解更多float的相关内容,可以阅读本专题下面的文章。

556

2024.04.28

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

98

2025.10.23

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

731

2023.08.22

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

15

2025.11.27

c语言union的用法
c语言union的用法

c语言union的用法是一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型,union的使用可以帮助我们节省内存空间,并且可以方便地在不同的数据类型之间进行转换。使用union时需要注意对应的成员是有效的,并且只能同时访问一个成员。本专题为大家提供union相关的文章、下载、课程内容,供大家免费下载体验。

122

2023.09.27

c语言union的用法
c语言union的用法

c语言union的用法是一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型,union的使用可以帮助我们节省内存空间,并且可以方便地在不同的数据类型之间进行转换。使用union时需要注意对应的成员是有效的,并且只能同时访问一个成员。本专题为大家提供union相关的文章、下载、课程内容,供大家免费下载体验。

122

2023.09.27

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

315

2023.08.02

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

78

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
CSS3 教程
CSS3 教程

共18课时 | 4.4万人学习

Sass 教程
Sass 教程

共14课时 | 0.8万人学习

Pandas 教程
Pandas 教程

共15课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号