Dre*_*ann 14 c++ c++17 stdoptional std-variant
std::variant可以进入一种称为“ 异常无价值 ”的状态。
据我了解,这是导致移动分配抛出异常的常见原因。不能保证该变体的旧值不再存在,预期的新值也不是。
std::optional,但是没有这种状态。cppreference提出了大胆的主张:
如果引发异常,则* this ...的初始化状态不变,即,如果对象包含一个值,则它仍然包含一个值,反之亦然。
如何std::optional避免变得“异常无价值”而std::variant不能避免?
Bar*_*rry 17
optional<T> 具有以下两种状态之一:
Tvariant仅当从一个状态转换到另一状态时,A 才能进入无值状态,否则转换会抛出-因为您需要以某种方式恢复原始对象,并且为此采取的各种策略需要额外的存储1,堆分配2或空状态3。
但是对于optional,从过渡T到空只是破坏。因此,仅当T析构函数抛出时才抛出,而实际上谁在乎。从空状态过渡到T不是问题-如果抛出该异常,则很容易恢复原始对象:空状态为空。
具有挑战性的情况是:emplace()当我们已经有一个时T。我们一定需要销毁原始对象,所以如果Emplace结构抛出异常该怎么办?使用optional,我们有一个已知的方便的空状态可以回退-因此设计仅是要这样做。
variant从没有那么容易的状态恢复的问题。
1由于boost::variant2做。
2由于boost::variant做。
3我不确定执行此操作的变体实现,但是有人提出了一个设计建议,如果它保留an 并抛出异常,则variant<monostate, A, B>可以转换为monostate状态。AB
std::optional 很简单:
它包含一个值并分配了一个新值:
容易,只需委托给赋值运算符并让它处理它即可。即使在例外情况下,仍然会剩下一个值。
它包含一个值,并且该值已删除:
很简单,dtor不能抛出。标准库通常假定用户定义的类型使用该库。
它不包含任何值,并且分配了一个值:
面对构造异常时恢复为无值非常简单。
它不包含任何值,也没有分配任何值:
琐碎的。
std::variant当存储的类型不变时,具有相同的轻松时间。
不幸的是,当分配了其他类型时,必须先销毁先前的值,然后再构造新的值,以取代它!
由于先前的值已经丢失,该怎么办?
将其标记为异常无价值,以使其具有稳定,有效但不理想的状态,并让异常传播。
可以使用额外的空间和时间来动态分配值,将旧值临时保存在某个地方,在分配值之前构造新值等,但是所有这些策略都很昂贵,只有第一种始终有效。
“异常无价值”是指您需要更改存储在变量中的类型的特定方案。这必然需要1)销毁旧值,然后2)在其位置创建新值。如果2)失败,则您无处可退(没有过多的开销,委员会无法接受)。
optional没有这个问题。如果对其包含的对象进行某些操作,则会引发异常,请这样。该对象仍然存在。这并不意味着对象的状态仍然有意义-不管抛出操作留下了什么。希望该操作至少具有基本的保证。
| 归档时间: |
|
| 查看次数: |
367 次 |
| 最近记录: |