gpt4 book ai didi

c++ - 为什么在移动赋值中需要 std::variant 成为 valueless_by_exception?

转载 作者:行者123 更新时间:2023-12-05 01:04:34 27 4
gpt4 key购买 nike

我已经看到关于 valueless_by_exception 方法的 cppreference 的以下注释:

A variant may become valueless in the following situations:

  • (guaranteed) an exception is thrown during the move initialization of the contained value during move assignment
  • (optionally) an exception is thrown during the copy initialization of the contained value during copy assignment

所以,这样的代码

std::variant<MyClass> var = {...};
var = myClassObj;

不需要使 var.valueless_by_exception() 等于 true(并且可能会使 var 保持其先前的状态),但是这段代码

std::variant<MyClass> var = {...};
var = std::move(myClassObj);

如果发生异常,保证 var.valueless_by_exception() 等于 true。

复制和移动分配之间的规范差异的实际原因是什么?

最佳答案

请注意,Cppreference 是在谈论不同的情况。当它说复制/移动分配时,它是在谈论复制/移动分配来自变体,而不是来自TT 的赋值在下一条语句中处理:

(optionally) an exception is thrown when initializing the contained value during a type-changing assignment

变体的移动分配失败总是会使目标变体毫无值(value)的原因是没有其他选择。

这里的问题是特定于分配的问题。当您将一个 variant 分配给另一个时,有两种可能性。这两个变体要么拥有相同的 Ti 类型,要么不拥有。

如果它们共享相同的 Ti,那么它们存储的类型之间的复制/移动分配可以直接发生。发生这种情况时,variant 为正在使用的 Ti 提供赋值操作的异常保证。变体本身在任何时候都不会变得毫无值(value)。它始终拥有一个实时的 Ti,它处于失败的复制/移动赋值运算符留下的任何状态。

但是,如果两个变体在 Ti 上不同,那么目标变体必须销毁其当前对象并通过复制/移动创建源类型 Ti 的新对象构造(不是赋值)。

如果变体提供了强大的异常保证,这意味着如果这个复制/移动构造失败,那么变体应该仍然保留它在赋值运算符之前拥有的对象类型和值。但是你会注意到这个对象在创建新对象之前被销毁了。这是因为 variant 存储了它所有的 Ts 的并集,因此它们都共享内存。你不能尝试在变体中创建一个 Ti 而不首先破坏那里的任何东西。

一旦被破坏,它就消失了,无法恢复。

所以现在我们有一个不包含原始类型的变体,我们未能在其中创建 Ti。那么……它是什么?

什么都没有。

从拷贝中变为无值(value)是可选的原因是,如果一个类型在复制构造中抛出而不是在移动构造中抛出(正如许多抛出复制类型所提供的那样),则可以使用两个对象来实现复制操作解决方案。您在销毁内部变量对象之前对堆栈临时进行复制初始化。如果成功,您可以销毁内部对象并从堆栈对象中移动构造。

委员会不想要求这个实现,但也不想禁止它。

关于c++ - 为什么在移动赋值中需要 std::variant 成为 valueless_by_exception?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71970051/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com