在解释与同事对对象的移动操作时,我基本上说移动操作不应该在容器中抛出异常,因为如果移动操作失败,则无法可靠地恢复原始对象。考虑到这一点,我想知道这是不是正确的,并且如果一个移动操作确实抛出,它可以将原始对象恢复到它的原始状态。
这样做的原因是,如果一个对象可以抛出,那么它会因为复制或将包含的对象从旧地址移动到新地址而抛出,但如果资源未能获取则抛出。所以所有的原始信息都应该存在。如果是这种情况,那么编译器是否应该无法反转它为重建原始对象所做的操作?
操作可能是一种方式,比如移动一个整数,但在这种情况下它可能只是终止应用程序,也许如果开发人员想避免单向操作可以使用交换方法。
这只能在默认移动运算符上实现,就像有任何其他逻辑一样,编译器可能很难进行反向部分变换。
我是否过于简化了事情?有没有我遗漏的东西,如果没有非投掷移动构造函数/操作符,容器不会移动对象?
您可以在容器中使用投掷移动的类型 vector
这可以移动他们的元素。但是,这样的容器 将不会 使用投掷移动操作。
假设你有一个 vector
10投掷移动元素。而且 vector
需要调整自己的大小。所以它将5个对象移动到新的内存中,但是第6个抛出。嗯,那没关系;构造失败,所以假设第6个对象的值很好。也就是说,无论那种类型的异常保证是什么,它将是如何工作的。
但是,因为一个物体的运动失败了, vector
需要移动最后5个对象 背部 从那以后到第一个阵列 vector
正试图提供强有力的例外保证。这是一个问题,因为回来了 本身就会失败。
当修复故障本身的过程失败时,C ++通常没有有效的答案。你可以在例外中看到;您不能从由于异常失败而在展开过程中调用的析构函数中发出异常。 std::terminate
在这种情况下发生。
同样的道理 vector
。如果搬回失败, vector
没有理智的答案。因此,如果 vector
不能 保证 恢复其先前的数组状态是 noexcept
,然后它将使用复制,因为这可以提供该保证。
首先,我很难想象在移动操作中获取资源的对象。想一想 - unique_ptr
只是传递指针而不获取任何东西,相同的 shared_ptr
。 string
, vector
,所有的包含等只是窃取指向早期默认或复制构造函数中获取的资源的指针。我觉得从移动构造函数抛出就像从析构函数中抛出一样。当然,继续拍你自己的膝盖。但好吧,我可以接受存在的例外情况。
所以让我们转到第二点 - 当移动时,实际上两个对象(移动和移动)都是无效的。从这种情况回滚将需要额外的“魔术”功能来调用其中一个。所以似乎数据无法修复,因为标准没有定义这样的功能。