对于某些标准库类,合法访问其部分内容可能会失败。通常,您可以在某些可能的投掷方法和标记为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
! (除了在switch
上variant::index()
的可怕解决方法之外)
在我看来,这似乎是对设计的严重监督……还是有原因吗?如果我对监督的看法是正确的,是否有计划将其修正为标准?
答案 0 :(得分:1)
这意味着要访问变体,您不能选择自己承担责任
可以。如果您将值分配或放置到现有的variant
中,则“异常无价值”状态将仅发生。此外,根据定义,只有在这些过程中实际抛出异常时,才会发生这种情况。那不是一个随机发生的variant
状态。
如果您有责任确保自己从不放置/分配变量,或者在这种情况下不要使用抛出的类型,或者对由此引起的任何异常做出回应,以使{{ 1}}不会引起它的骚扰(即:如果抛出variant
,则您的应用程序不会捕获它;它只会关闭),那么您不必在意这种可能性。< / p>
基本上,如果您已经在进行 编码以避免异常,则bad_alloc
的非noexcept
状态是无关紧要的。除非引发异常,否则visit
永远不会进入“异常无价值”。