0

0

c++的std::variant如何安全地访问其存储的值? (std::get和std::visit)

穿越時空

穿越時空

发布时间:2026-01-10 14:49:10

|

478人浏览过

|

来源于php中文网

原创

std::get会崩溃,因其不检查运行时类型,类型或索引不匹配时抛std::bad_variant_access;应先用std::holds_alternative确认类型或在std::visit分支内使用。

c++的std::variant如何安全地访问其存储的值? (std::get和std::visit)

std::get 会崩溃?先确认类型再取值

std::get 是最直接的访问方式,但它不检查运行时实际存储的类型——如果索引或类型不匹配,会抛出 std::bad_variant_access。这不是“可能出错”,而是“必然崩溃”(在 Release 模式下甚至可能是未定义行为)。

安全做法是:**只在确定类型的前提下用 std::get**。比如你刚用 std::holds_alternative 检查过,或者在 std::visit 的 lambda 内部、已知当前分支对应某类型时使用。

  • ✅ 正确:
    if (std::holds_alternative(v)) {
        int x = std::get(v); // 类型已确认
    }
  • ❌ 危险:
    int x = std::get(v); // v 可能存的是 std::string —— 崩溃
  • ⚠️ 注意:std::get(v) 按索引取值,但索引依赖 std::variant 模板参数顺序,易随定义变更而失效;优先用 std::get

std::visit 是默认的安全入口,别绕开它

std::visit 强制你为每种可能的类型提供处理逻辑,天然覆盖所有情况,是访问 std::variant 的推荐起点。它不抛异常(除非你写的 visitor 自己 throw),也避免了类型误判。

常见陷阱是写不全的 lambda:漏掉某个备选项,编译就报错(C++17 起是硬性要求)。

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

LALALAND
LALALAND

AI驱动的时尚服装设计平台

下载
  • ✅ 完整覆盖:
    std::visit([](const auto& val) {
        using T = std::decay_t;
        if constexpr (std::is_same_v) {
            std::cout << "int: " << val << "\n";
        } else if constexpr (std::is_same_v) {
            std::cout << "string: " << val << "\n";
        } else if constexpr (std::is_same_v) {
            std::cout << "double: " << val << "\n";
        }
    }, v);
  • ⚠️ 注意:std::visit 要求所有分支返回相同类型,否则编译失败;可用 std::monostate 或统一返回 void 避免推导冲突
  • ⚠️ 性能:现代编译器对 std::visit 通常能内联并优化成跳转表,不必担心 runtime 开销

需要返回值?用带返回类型的 visitor + std::optional 处理不确定场景

如果访问逻辑本身不能 100% 确定输入 variant 的内容(比如解析外部数据后构造的 variant),又不想 throw 异常,可以用 std::optional 封装结果。

  • ✅ 安全提取数值(失败则返回空):
    auto try_get_int = [](const auto& v) -> std::optional {
        if constexpr (std::is_same_v, int>) {
            return v;
        } else {
            return std::nullopt;
        }
    };
    std::optional result = std::visit(try_get_int, v); // result.has_value() 判断是否成功
  • ⚠️ 注意:不要在 visitor 里捕获 std::bad_variant_access——std::visit 根本不会抛这个异常;它只在 visitor 执行中主动 throw 时才传播
  • ⚠️ 兼容性:std::optional 是 C++17 特性;若需 C++14,可用 boost::optional 或自定义 tagged union

std::get_if:比 std::get 更谨慎的指针式访问

std::get_if(&v) 返回 T*,如果当前 variant 不含 T 则返回 nullptr。它不抛异常,适合“尝试访问、失败即跳过”的场景,比先 holds_alternativeget 少一次类型比较。

  • ✅ 推荐用于条件分支前快速试探:
    if (auto* p = std::get_if(&v)) {
        use(*p); // 安全解引用
    } else if (auto* s = std::get_if(&v)) {
        use(*s);
    }
  • ⚠️ 注意:std::get_if 不能用于 const variant 得到非 const 指针;要取 const 值,用 std::get_if 或加 const_cast(不推荐)
  • ⚠️ 和 std::holds_alternative 的区别:后者只判断,前者顺便给出访问入口;两者底层都查同一个 type index,性能无差异

真正容易被忽略的是:std::variant 的安全性不来自某个函数,而来自你是否让所有可能路径都被显式覆盖。用 std::visit 是最稳妥的起点;绕开它直奔 std::get,等于把类型安全责任推给程序员自己——而人在疲劳时一定会漏掉某个 std::string 分支。

相关专题

更多
string转int
string转int

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

315

2023.08.02

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

520

2023.09.20

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

175

2023.11.23

java中void的含义
java中void的含义

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

95

2025.11.27

lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

202

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

189

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

41

2026.01.05

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

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

25

2026.01.09

c++框架学习教程汇总
c++框架学习教程汇总

本专题整合了c++框架学习教程汇总,阅读专题下面的文章了解更多详细内容。

23

2026.01.09

热门下载

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

精品课程

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

共61课时 | 3.4万人学习

C# 教程
C# 教程

共94课时 | 6.4万人学习

C 教程
C 教程

共75课时 | 4万人学习

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

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