Den*_*kiy 19 c++ variant c++17
根据投掷的cppreference std::get,如果包含的类型不是预期的类型.这意味着标准库必须检查每次访问(libc ++).variantstd::bad_variant_accessvariant
这个决定的理由是什么?为什么它不是未定义的行为,就像C++中的其他地方一样?我可以解决吗?
Jus*_*tin 11
当前的API std::variant没有未经检查的版本std::get.我不知道为什么这样做是标准化的; 我说的任何东西都只是在猜测.
但是,您可以通过编写接近所需的行为*std::get_if<T>(&variant).如果在那时variant没有保留T,则std::get_if<T>返回nullptr,因此解除引用它是未定义的行为.因此编译器可以假设变体成立T.
实际上,这不是编译器最容易的优化.与简单标记的联合相比,它发出的代码可能不太好.以下代码:
int const& get_int(std::variant<int, std::string> const& variant)
{
return *std::get_if<int>(&variant);
}
Run Code Online (Sandbox Code Playgroud)
get_int(std::variant<int, std::string> const&):
xor eax, eax
cmp dword ptr [rdi + 24], 0
cmove rax, rdi
ret
Run Code Online (Sandbox Code Playgroud)
它正在比较变量的索引并在索引正确时有条件地移动返回值.尽管指数的UB不正确,但clang目前无法优化比较.
有趣的是,返回an int而不是引用可以优化检查:
int get_int(std::variant<int, std::string> const& variant)
{
return *std::get_if<int>(&variant);
}
Run Code Online (Sandbox Code Playgroud)
发出:
get_int(std::variant<int, std::string> const&):
mov eax, dword ptr [rdi]
ret
Run Code Online (Sandbox Code Playgroud)
您可以使用__builtin_unreachable()或帮助编译器__assume,但gcc是目前唯一能够在您执行此操作时删除检查的编译器.
为什么它不是未定义的行为,就像c ++中的其他地方一样?我可以解决吗?
是的,有一个直接的解决方法.如果您不想要类型安全,请使用plain union而不是a std::variant.正如你在引用中所说:
类模板std :: variant表示类型安全联合.
目的union是让一个对象可以从多种不同类型中的一种中获取值.union在任何给定时间,只有一种类型的"有效",具体取决于已分配的成员变量:
union example {
int i;
float f;
};
// code block later...
example e;
e.i = 10;
std::cout << e.f << std::endl; // will compile but the output is undefined!
Run Code Online (Sandbox Code Playgroud)
std::variant概括了一段union时间添加类型安全性以帮助确保您只访问正确的数据类型.如果您不想要这种安全性,可以随时使用union.
这个决定的理性是什么?
我个人不知道这个决定的理由是什么,但你总是可以看一下C++标准化委员会的论文,以便对这个过程有所了解.
| 归档时间: |
|
| 查看次数: |
949 次 |
| 最近记录: |