【问题标题】:C++ Move semantics and ExceptionsC++ 移动语义和异常
【发布时间】:2011-06-11 13:13:56
【问题描述】:

在即将发布的 C++0x 标准中,当在移动构造函数内/期间抛出异常时会发生什么?

原始对象会保留吗?还是原始对象和移动对象都处于未定义状态?该语言提供了哪些保证?

【问题讨论】:

  • 我想知道这是否类似于析构函数,如果它抛出异常,它只是一件坏事。我假设在大多数情况下你可以移动而无需做任何可能抛出的事情,因为你(通常)只是移动指针......
  • 那么你的意思是不应该抛出异常,因为被复制的成员的状态在移动操作期间永远不会改变?
  • 排序-类似于您用来证明swap 不能抛出的归纳论证。作为基本情况,重新分配和复制原语永远不会抛出。作为归纳步骤,具有一些数据成员的对象的移动构造函数可以在不抛出的情况下移动这些数据成员(归纳假设!),因此可以在不抛出的情况下移动自身。不过,独立地,我仍然想知道您的问题的正确答案是什么。

标签: c++ exception c++11 move-semantics


【解决方案1】:

我相信标准委员会最初试图让构造函数不允许抛出异常,但(至少在今天)发现尝试强制执行存在太多陷阱。

提案 N3050,“允许移动构造函数抛出(Rev 1)”,已被纳入标准草案。本质上,该提案增加了移动构造函数抛出的能力,但不允许将“抛出”移动用于需要强异常安全保证的某些操作(如果非抛出移动,库将回退到复制对象) t 可用)。

如果将移动构造函数标记为非抛出 (noexcept) 并抛出异常,则将调用 std::terminate()。

还值得阅读 David Abrahams 的博客文章,该文章讨论了 N3050 旨在解决的问题:

【讨论】:

  • 感谢 David Abrahams 的文章 :)
  • 是的,我也发现整个 cpp-next 博客网站上大量有价值的文章非常有趣!
【解决方案2】:

取决于被移动的类型。当然,可以从移动 ctor 显式抛出异常,但也可以从移动 ctor 隐式调用子对象的复制 ctor。该复制ctor可能会做一些可能会抛出的事情,例如分配内存。因此,对于源对象,最低保证是原始值可能保留也可能不保留,但仍应处于可破坏状态。

对于被移动到的对象,它与当前 C++ 中的 ctor 抛出相同:销毁任何构造的基和成员,执行 ctor 的函数 try 处理程序(如果有),然后传播异常。详细信息在 N3225 §15.2p2 中。

特别注意,容器要求它们的分配器类型没有投掷移动 ctor:

分配器的这种移动构造不应通过异常退出。 [N3225 §23.2p8]

这允许容器移动分配器并在移动或复制项目时使用这些分配器清理它们的项目。

【讨论】:

    【解决方案3】:

    您的问题相当于一个关于例外保证的问题。有 3 种类型的例外保证(适用于函数):

    • 根本没有异常保证(不是真正的类型......但如果不关心此事,它可能会发生)
    • 基本异常保证:技术上正确,但功能上不正确(即没有资源泄漏,程序将终止而不会突然停止,但它可能会产生不希望的副作用,例如兑现付款但该命令未注册)
    • 强异常保证:All or Nothing(如事务),即要么一切正常,要么我们回滚到之前的状态。
    • 无抛出异常保证:这永远不会抛出,所以不用担心。

    当你编写你的函数时,你通常会选择现有的函数,它们有自己的保证。很难增加异常保证,即您通常会受到所使用的最弱保证的限制。

    W.r.t 你的问题,如果抛出异常,原始对象至少需要一个强异常保证

    那么,如果在 move-construction 期间抛出异常会发生什么?这取决于子对象表现出的保证以及您组合调用的方式...

    1. 如果从构造函数中抛出异常,则不会构建对象,并且所有构建的子对象都将被销毁,顺序相反。此规则也适用于移动构造函数
    2. 除非您将构造函数“包装”在 try catch 中并以某种方式恢复已移动的对象,否则它们将丢失资源。请注意,它们无论如何都必须处于可破坏状态,因此从技术上讲,该程序是正确的。

    就异常保证而言,这意味着默认情况下,如果所有子对象的构造函数至少满足基本异常保证,那么您的移动构造函数也会满足,无需特别注意。

    但是,即使所有子对象的构造函数都满足强异常保证,您也不太可能成功地让自己的移动构造函数满足它:这与链式事务不满足的问题相同产生一笔交易。

    如果只有一个子对象的构造函数可以抛出,并且它满足强异常保证,那么如果你先初始化抛出对象,你的移动构造函数自然会遇到它。

    希望这会有所帮助...例外是驯服的野兽:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-20
      • 1970-01-01
      • 1970-01-01
      • 2014-09-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多