根据cppreference如果 variant
中包含的类型不是预期的,则 variant
的 std::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);
}
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/