【问题标题】:Why I'm getting std::bad_variant_access with std::variant?为什么我用 std::variant 得到 std::bad_variant_access?
【发布时间】:2020-07-28 13:14:45
【问题描述】:

考虑:

#include <variant>
#include <iostream>

int main()
{
    double foo = 666.666;
    std::variant<double, uint64_t> v = foo;
    std::cout << std::get<uint64_t>(v) << std::endl;
    return 0;
}

这会导致:

terminate called after throwing an instance of 'std::bad_variant_access'
  what():  Unexpected index
Aborted (core dumped)

为什么?

我知道std::variant 将替代union。但是,如果这种基本的东西失败了,它有什么用呢?

【问题讨论】:

  • union 从来都不适合双关语。读取与上次写入不同的联合成员始终是未定义行为。
  • 您在变体中没有uint64_t。为什么你希望它给你一个?
  • 您将其分配为双精度数并将其读取为整数。你期待什么?与工会一起执行此操作会进入 UB 领域,因此获得例外会非常好。
  • "但是如果这种基本的东西失败了,它有什么用呢?"我认为这是基本成功的一个很好的例子:-)

标签: c++ c++17 ubuntu-18.04 variant gcc7


【解决方案1】:

我知道 std::variant 将替代 union。

是的。的种类。但是您的误解似乎与 C++ 中的联合有关。来自cppreference

从最近未写入的联合成员中读取是未定义的行为。许多编译器作为非标准语言扩展实现了读取联合的非活动成员的能力。

请注意,这与 C 不同,这是导致 C++ 也允许访问非活动成员这一常见误解的根本原因。

为什么?

因为std::variant 模仿联合但增加了一些安全性,而std::get 是...

基于索引的值访问器:如果 v.index() == I,则返回对存储在 v 中的值的引用。否则,抛出 std::bad_variant_access。 调用格式错误如果我不是变体中的有效索引。

.

但是如果这种基本的东西失败了有什么好处呢?

C++ 中的联合从来就不是这样使用的。当您想将两个或多个值压缩到同一个内存中时(但在任何时候只使用其中一个),联合是为了节省内存。我从来没有遇到过真正的用例。 std::variant 然而,是对 C++ 类型的一个很好的补充。更大的图景是,很久以来就有所谓的产品类型,比如std::pair&lt;T1,T2&gt;,从某种意义上说,它们可以表示的一组值是T1 x T2。使用std::variant(和std::any),现在C++ 也有适当的(= 具有你从未从联合中得到的类型安全的程度)和类型,即std::variant&lt;T1,T2&gt; 可以表示的值集是T1 + T2(对不起使用草率的符号,希望它是清楚的)。

【讨论】:

    【解决方案2】:

    std::variant 是一个“类型安全的联合”,这意味着它会检查您从中获得的内容是否是最后存储在其中的类型。在此示例中,您正在存储 double,但尝试获取 uint64_t

    在此处查看文档: https://en.cppreference.com/w/cpp/utility/variant/get

    基于类型的值访问器:如果 v 持有替代 T,则返回对存储在 v 中的值的引用。否则,抛出 std::bad_variant_access。如果 T 不是 Types 的唯一元素,则该调用格式不正确......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-18
      • 2022-01-06
      • 2017-03-05
      • 2019-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-18
      相关资源
      最近更新 更多