代码之家  ›  专栏  ›  技术社区  ›  Adrian

有没有可能让类型具有可以放入容器的移动操作?

  •  11
  • Adrian  · 技术社区  · 8 年前

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

    这样做的原因是,如果一个对象可以抛出,那么它不会因为复制或移动包含的对象而抛出,而是因为无法获取资源而抛出。所以所有的原始信息都应该在那里。如果是这种情况,那么编译器是否应该不能反转它为重建原始对象所做的操作?

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

    这只能在默认的move操作符上实现,就像有其他逻辑一样,编译器可能很难执行反向部分转换。

    我是不是过于简单化了?我是否遗漏了一些东西,这些东西可以防止容器在没有非抛出移动构造函数/运算符的情况下移动对象?

    2 回复  |  直到 8 年前
        1
  •  10
  •   Nicol Bolas    8 年前

    你可以在容器中使用类型和投掷动作,比如 vector 可以移动它们的元素。然而,这种容器 不会 使用投掷动作操作。

    假设你有一个 矢量 10个投掷动作元素。以及 矢量 需要调整自身大小。所以它将5个对象移动到新的内存中,但第6个对象被抛出。好吧,没关系;建造失败了,所以假设第6个物体的价值是可以的。也就是说,无论这种类型的例外保证是什么,都将是事情的工作方式。

    但是,因为一个物体的运动失败了, 矢量 需要移动最后5个对象 后面 到第一个数组, 矢量 试图提供强有力的例外保证。这是个问题,因为搬回去 会自己失败 .

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

    同样的道理 矢量 . 如果撤军失败, 矢量 没有理智的回答。因此,如果 矢量 不能 保证 恢复其以前的数组状态是 noexcept ,那么它将使用复制,因为这可以提供保证。

        2
  •  0
  •   bartop    8 年前

    首先,我很难想象在移动操作中获取资源的对象。想想看- unique_ptr 只需传递指针而不获取任何内容,同样适用于 shared_ptr . string , vector 所有的containters等,只是窃取指向在默认或复制构造函数中获取的资源的指针。我觉得从move构造函数抛出就像从析构函数抛出。当然,去吧,射中自己的膝盖。但好吧,我可以接受这个例外的存在。

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

    推荐文章