对于某些标准库类,访问其部分内容可能会合法地失败。通常你可以选择一种潜在的投掷方法,一种标记为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
ing在variant::index()
上的可怕的解决方法)
对我来说,这看起来像一个非常糟糕的设计疏忽...或者有这样的理由?如果我对监督是正确的,是否有一项计划在标准中解决这个问题?
这意味着对于访问变体,您无法自己选择承担责任
你当然可以。只有在将值赋值给现有的variant
时才会出现“无价值异常”状态。此外,根据定义,只有在这些过程中实际抛出异常时才会发生这种情况。这不是一个曾经发生在随机的variant
的状态。
如果您承担责任确保您永远不会置换/分配给变体,或者您使用的类型从未在这些情况下抛出,或者您对这样做的任何异常做出响应,以致激发它的variant
是没有被谈论(即:如果bad_alloc
被抛出,你的应用程序没有抓住它;它只是关闭),那么你不必关心这种可能性。
基本上,如果你已经编码以避免例外,noexcept
的非visit
状态是无关紧要的。除非抛出异常,否则任何variant
都不会进入“无价值的异常”。