std::variant
可以进入名为“valueless by exception ”的状态。
据我了解,造成这种情况的常见原因是移动分配抛出异常。变体的旧值不再保证存在,预期的新值也不再存在。
然而,std::Optional
没有这样的状态。 cppreference 做出了大胆的声明:
If an exception is thrown, the initialization state of *this ... is unchanged, i.e. if the object contained a value, it still contains a value, and the other way round.
std::Optional
如何能够避免变得“因异常而毫无值(value)”,而 std::variant
却不能?
最佳答案
optional<T>
有两种状态之一:
- 一个
T
- 空
一个variant
如果转换会抛出异常,则只能在从一种状态转换到另一种状态时进入无值(value)状态 - 因为您需要以某种方式恢复原始对象,并且执行此操作的各种策略需要额外的存储1、堆分配< support>2,或空状态3。
但是对于 optional
,从 T
过渡空虚只是一种破坏。所以只有 T
才会抛出异常的析构函数抛出,此时谁在乎呢。并从空过渡到 T
不是问题 - 如果抛出异常,很容易恢复原始对象:空状态是空的。
具有挑战性的案例是:emplace()
当我们已经有了 T
。我们必然需要销毁原始对象,那么如果 emplace 构造抛出异常我们该怎么办?与optional
,我们有一个已知的、方便的空状态可以回退 - 所以设计就是为了做到这一点。
variant
问题在于没有那么容易恢复到的状态。
1 作为 boost::variant2
确实如此。
2 作为 boost::variant
确实如此。
3 我不确定执行此操作的变体实现,但有一个设计建议 variant<monostate, A, B>
可以转换为 monostate
说明它是否持有 A
以及过渡到 B
扔了。
关于c++ - std::Optional 怎么永远不会 "valueless by exception"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57696187/