c++ - 为什么 std::get for variant 会引发失败而不是未定义的行为?

标签 c++ variant c++17

根据cppreference如果 variant 中包含的类型不是预期的,则 variantstd::get 会抛出 std::bad_variant_access一。这意味着标准库必须检查每个访问 (libc++) .

做出这个决定的理由是什么?为什么它不是未定义的行为,就像 C++ 中的其他地方一样?我可以解决它吗?

最佳答案

std::variant 的当前 API没有 std::get 的未检查版本.我不知道为什么它是这样标准化的。我说的都只是猜测。

但是,您可以通过编写 *std::get_if<T>(&variant) 来接近所需的行为。 .如果 variant不持有 T那个时候, std::get_if<T> 返回 nullptr ,因此取消引用它是未定义的行为。因此,编译器可以假设变体持有 T .


在实践中,这并不是编译器要做的最简单的优化。与简单的标记 union 相比,它发出的代码可能没有那么好。以下代码:

int const& get_int(std::variant<int, std::string> const& variant)
{
    return *std::get_if<int>(&variant);
}

发射 this with clang 5.0.0 :

get_int(std::variant<int, std::string> const&):
  xor eax, eax
  cmp dword ptr [rdi + 24], 0
  cmove rax, rdi
  ret

它正在比较变体的索引并在索引正确时有条件地移动返回值。即使索引不正确会导致 UB,clang 目前无法优化比较。

有趣的是,返回 int而不是引用 optimizes the check away :

int get_int(std::variant<int, std::string> const& variant)
{
    return *std::get_if<int>(&variant);
}

发射:

get_int(std::variant<int, std::string> const&):
  mov eax, dword ptr [rdi]
  ret

您可以使用 __builtin_unreachable() 来帮助编译器或 __assume , 但 gcc 目前是唯一的编译器 capable of removing the checks当你这样做的时候。

关于c++ - 为什么 std::get for variant 会引发失败而不是未定义的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48817080/

相关文章:

c++ - 具有由整数确定的固定数量参数的函数

C++ new int[0]——它会分配内存吗?

c++ - 如何访问存储在 std::variant 中的类的方法

c++ - 实现多态性

c++ - 使用 std::get<index> 访问 std::variant

c++ - 一旦找到所需的替代方案,就跳出 std::visit

使用模板定义多个函数的 C++ 通用方法

c++ - Linux 上的 file.open() 无法打开我的文件,如何解决?

c++ - 打印整个文本文件而不显示空行,C++

c++ - 如何测试加密算法?