有没有可能让类型具有在容器中抛出的移动操作?

Could it be possible to have types with move operations that throw in containers?

在和同事解释对象的移动操作时,我基本上说移动操作不应该在容器中抛出异常,因为如果移动操作失败,那么就没有办法可靠地带回原始对象。仔细考虑一下,我想知道这是否不正确,如果确实抛出一个移动操作,它可以将原始对象恢复到其原始状态。

之所以这样,是因为如果一个对象可以抛出,那么它不会因为将包含的对象从旧地址复制或移动到新地址而抛出,而是在获取资源失败时抛出。所以所有原始信息应该仍然存在。如果是这种情况,那么编译器是否应该无法反转它为重构原始对象所做的操作?

一个操作可能是单向的,比如移动一个整数,但在那种情况下,它可能只是终止应用程序,如果开发人员想要避免单向操作,也许可以使用交换方法相反。

这只有在默认移动运算符上才有可能,因为如果有任何额外的逻辑,编译器可能很难进行反向部分转换。

我是不是把事情简单化了?有什么我错过的东西可以防止容器在没有非投掷移动的情况下移动物体 constructor/operator?

您可以在像 vector 这样可以移动其元素的容器中使用带有投掷动作的类型。然而,这样的容器不会使用抛出移动操作。

假设您有一个 vector 的 10 个投掷移动元素。 vector 需要自行调整大小。所以它将 5 个对象移动到新内存,但第 6 个抛出。好吧,没关系;构造失败,所以假设第 6 个对象的值是好的。也就是说,无论该类型的异常保证是什么,事情都会如何运作。

但是,由于一个对象移动失败,vector需要将最后5个对象移回到第一个数组,因为vector正在尝试提供强大的异常保证。这是个问题,因为向后移动 本身可能会失败

当修复故障的过程本身失败时,C++ 通常没有有效的答案。您可以在例外情况中看到这一点;由于异常失败,您不能从在展开过程中调用的析构函数发出异常。 std::terminate 就是这种情况。

vector也是如此。如果返回失败,vector 没有理智的答案。因此,如果 vector 不能 保证 恢复其先前的数组状态是 noexcept,那么它将使用复制,因为这可以提供这种保证。

首先,我很难想象在移动操作中获取资源的对象。想一想 - unique_ptr 只是传递指针而不获取任何东西,shared_ptr 也是如此。 stringvector、所有的containters等只是窃取指向早先在默认或复制构造函数中获取的资源的指针。我觉得从移动构造函数中抛出就像从析构函数中抛出一样。当然,继续,朝自己的膝盖开枪。但是好吧,我可以接受存在例外情况。

所以让我们转到第二点 - 移动时,有时两个对象(移动自和移动到)实际上都是无效的。要从这种情况回滚,需要调用额外的 'magic' 函数来修复其中一个问题。所以似乎无法修复数据,因为标准没有定义这样的功能。