【问题标题】:Why does std::vector allow the use of a throwable move constructor for the type it contains?为什么STD :: Vector允许使用它包含的类型的Throwable Move构造函数?
【发布时间】:2019-09-16 21:15:34
【问题描述】:

显然,std::move_if_noexcept() 将调用移动构造函数,即使它没有标记为 noexcept,如果没有可用的复制构造函数。

来自cpprefeerence.com(强调我的):

注意事项

例如,std::vector::resize 使用它,它可能必须分配新存储空间,然后将元素从旧存储空间移动或复制到新存储空间。如果在此操作过程中发生异常,std::vector::resize 会撤消它到此为止所做的一切,这只有在使用std::move_if_noexcept 来决定是使用移动构造还是复制构造时才有可能。 (除非复制构造函数不可用,在这种情况下,无论哪种方式都使用移动构造函数,并且可以放弃强异常保证)

由于std::vector 在重新分配时使用此函数,这可能会使向量和可能的应用程序处于未确定状态。那么,为什么会允许这样做呢?

【问题讨论】:

  • 您想从设计会议的会议中获得报价,或者这对软件有什么好处?其次,IIRC,这些规则随着时间的推移发生了变化。您想要回答哪个 C++ 的确切版本? C++11?我要求您尽可能缩小您的问题范围。
  • @Yakk-AdamNevraumont,好处,尽管引用可能有助于理解它们。如果规则随着时间而改变,那么了解它的演变到当前状态也可能很有用。仅在引入时将其标记为 c++11。
  • 您是否有另一种行为?是否根本不可能将vector 用于此类类型,即使没有强有力的保证,它是否有用?
  • @DavisHerring,如果你没有这样的保证,那会发生什么?新位置及其所有已移动的元素都被销毁,旧位置中的一些元素处于有效但未确定的状态。所以我想不会发生资源泄漏,可以吗?任何可能引用向量的东西都必须考虑到这一点,我想这是可行的。如果抛出的异常被包装在另一个中以说明什么范围无效,则可能很有用。
  • @Adrian:您得到了基本保证——vector 处于有效但未指定的状态,没有泄漏,您可能能够分辨出哪个元素未能从异常中移动。

标签: c++ c++11


【解决方案1】:

假设你正在做 vector 正在做的事情,而它会使用 move_if_noexcept。也就是说,您有一些对象obj,您需要从obj 构造一个该类型的新值。之后,您将删除obj。这是移动对象的主要情况,所以vector 会尽可能地这样做。

如果移动是noexcept,那么移动obj 根据定义是异常安全的。如果它不是noexcept,那么你需要问:如果移动构造函数抛出会发生什么?在这种情况下,obj 的状态是什么?答案是……你不知道。更糟糕的是,您已经成功移动的任何对象的状态如何?你能把它们移回吗?

然而,当谈到复制构造函数时,您确实知道。复制构造函数将const& 传递给源对象。所以根据定义,一个失败的复制操作不能修改obj(是的,我们知道你可以const_cast,但这会让你的复制构造函数成为一个谎言。谎言就像这就是为什么auto_ptr 不再存在的原因,我猜想在标准中全面禁止撒谎的复制构造函数)。因此,在失败的副本上,obj 处于其原始状态。

因此,如果运动可以抛出,则首选复制,因为这提供了强大的异常保证:一旦发生异常,一切都会恢复原状。

但是,如果您唯一的选择是投掷动作,那么您有两个选择:使这种类型永远不能与vector 一起使用,或者提供任何保证该类型的异常本身提供运动失败。而后者是被选择的。

这是允许的,因为这是你要求的。您选择的类型不允许强异常保证,因此无法提供。但是您仍然可以制作此类类型的vector;您只需要处理不可复制的移动失败的可能性。

而且由于你是那种使用无法提供强大异常保证的类型的人,你显然必须知道如何处理这些场景,对吧?

【讨论】:

  • 不要特别喜欢用第二人称来表达,好像我参与了这个决定。除非陈述/问题是专门针对我的,否则应该以第三人称重新措辞,因为这有点令人困惑。
  • @Adrian:“你”是用户。如果用户是给vector 这样的类型,那么那个用户......就是你。我不明白为什么使用第二人称会有什么不同。如果它让你感觉更好,那就把它想象成皇家的“你”。
猜你喜欢
  • 2013-12-08
  • 1970-01-01
  • 1970-01-01
  • 2010-10-04
  • 2015-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多