是否可以使用带有容器的移动操作的类型?

时间:2018-05-29 17:40:01

标签: c++ c++11 stl c++14 stdmove

在解释与同事对对象的移动操作时,我基本上说移动操作不应该在容器中抛出异常,因为如果移动操作失败,则无法可靠地恢复原始对象。考虑到这一点,我想知道这是不正确的,并且如果一个移动操作确实抛出,它可以将原始对象恢复到它的原始状态。

这样做的原因是,如果一个对象可以抛出,那么它会因为复制或将包含的对象从旧地址移动到新地址而抛出,但如果资源未能获取则抛出。所以所有的原始信息都应该存在。如果是这种情况,那么编译器是否应该无法撤消它为重建原始对象所做的操作?

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

这只能在默认移动运算符上实现,就像有任何其他逻辑一样,编译器可能很难进行反向部分变换。

我是否过于简化了事情?是否有一些我错过的东西,使容器不移动对象而没有非投掷移动构造函数/操作符?

2 个答案:

答案 0 :(得分:10)

你可以使用在vector等容器中投掷移动的类型来移动它们的元素。但是,此类容器不会使用抛出移动操作。

假设您有10个投掷移动元素的vector。而vector需要调整自己的大小。所以它将5个对象移动到新内存,但是第6个抛出。嗯,那没关系;构造失败,所以假设第6个对象的值很好。也就是说,无论那种类型的异常保证是什么都将起作用。

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

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

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

答案 1 :(得分:0)

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

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