【发布时间】:2019-05-25 13:54:05
【问题描述】:
对于某些标准库类,对其部分内容的访问可能会合法地失败。通常你可以在一些潜在的抛出方法和标记为noexcept的方法之间进行选择。后者省去了对前提的检查,所以如果你想自己承担责任,你可以。这可以在不允许使用异常或修复性能瓶颈的情况下使用。
示例 1:std::vector 元素访问:
std::vector<int> vec;
vec.at(n) // throws std::out_of_range
vec[n] // potentially UB, thus your own responsibility
示例 2:std::optional 访问:
std::optional<int> optn;
optn.value() // throws std::bad_optional_access
*optn // potentially UB, thus your own responsibility
现在转到std::variant。直接访问替代方案有点遵循这种模式:
std::variant<std::string, int> var;
std::get<int>(var) // potentially throwing std::bad_variant_access
*std::get_if<int>(&var) // potentially UB, thus your own responsibility
但是这次签名改变了,我们必须注入*和&。这样做的缺点是我们没有获得自动移动语义。还有一件事要记住...
但如果您查看std::visit(Visitor&& vis, Variants&&... vars),情况会变得更糟。没有 noexcept 替代它,虽然它只会抛出
如果 vars 中的任何变体是 valueless_by_exception。
这意味着访问变体你不能选择自己承担责任,如果你别无选择,必须避免例外,你根本不能用标准工具访问std::variants! (除了switching 在variant::index() 上的可怕解决方法)
在我看来,这似乎是一个非常糟糕的设计疏忽……还是有原因?如果我对疏忽的看法是正确的,是否有计划在标准中解决这个问题?
【问题讨论】:
标签: c++ c++17 variant noexcept