noexcept访问std :: variant

时间:2018-12-27 14:32:29

标签: c++ c++17 variant noexcept

对于某些标准库类,合法访问其部分内容可能会失败。通常,您可以在某些可能的投掷方法和标记为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! (除了在switchvariant::index()的可怕解决方法之外)

在我看来,这似乎是对设计的严重监督……还是有原因吗?如果我对监督的看法是正确的,是否有计划将其修正为标准?

1 个答案:

答案 0 :(得分:1)

  

这意味着要访问变体,您不能选择自己承担责任

可以。如果您将值分配或放置到现有的variant中,则“异常无价值”状态将仅发生。此外,根据定义,只有在这些过程中实际抛出异常时,才会发生这种情况。那不是一个随机发生的variant状态。

如果您有责任确保自己从不放置/分配变量,或者在这种情况下不要使用抛出的类型,或者对由此引起的任何异常做出回应,以使{{ 1}}不会引起它的骚扰(即:如果抛出variant,则您的应用程序不会捕获它;它只会关闭),那么您不必在意这种可能性。< / p>

基本上,如果您已经在进行 编码以避免异常,则bad_alloc的非noexcept状态是无关紧要的。除非引发异常,否则visit永远不会进入“异常无价值”。