std :: vector :: push_back是否有前置条件?

时间:2013-01-05 04:53:00

标签: c++ c++11 language-lawyer move-constructor preconditions

comments on Andrzej's move constructor article中,我发布了一个从对象移动的任何成员函数,它没有前置条件。我将示例std::vector::front作为一个函数,您无法调用移动的std::vector,因为它具有向量不为空的前提条件。我将std::vector::emptystd::vector::push_backstd::vector::reserve的示例作为您可以(但不应该)调用移动std::vector的函数,因为它们没有先决条件。

然而,这让我思考。 std::vector::push_back要求主机系统上有足够的连续内存。这不是std::vector对象的要求,而是对它运行的系统的要求,但在我看来这仍然是一个先决条件。

移动构造函数将对象保留在有效但未指定状态的上下文是什么,它是否适用于std::vector::push_back的潜在内存不足情况?特别是,如果std::vector::push_back在移动之前有效,是否可以保证工作(忽略其他进程使用内存等问题)?

供参考:§17.6.3.1

Table 20 — MoveConstructible requirements [moveconstructible]
Expression  Post-condition
T u = rv;   u is equivalent to the value of rv before the construction
T(rv)       T(rv) is equivalent to the value of rv before the construction
rv’s state is unspecified [ Note:rv must still meet the requirements of the library compo-
nent that is using it. The operations listed in those requirements must work as specified
whether rv has been moved from or not. — end note ]

2 个答案:

答案 0 :(得分:3)

如果内存不足,则push_back会以std::bad_alloc例外退出,后置条件不适用。 vector对象保持原始状态。

当向量达到容量时,会发生这种情况:

  1. 分配更大的块。如果这会引发bad_alloc异常,请将其传递给用户。什么都没有被修改过。
  2. 如果类型不可移动,或可移动但移动构造函数可能抛出异常,则将序列的元素复制到更大的块中。如果构造函数抛出异常,则销毁较大块中已有的所有内容,然后释放它,然后重新抛出异常。
  3. 如果类型是可移动的并且移动构造函数是noexcept,则将元素移动到更大的块中。这必须成功。如果违反noexcept规范,则实施不必尝试将事情移回(这可能会,也可能会失败。)
  4. 销毁原始内存块并保留新内存块。
  5. “有效但未指定”在此上下文中没有任何更深层的含义。用户根本不应该对其中的内容做出假设。但检查它以发现内容,或忽略内容并添加更多内容都很好。

    逻辑上,任何对象都应该留空或处于原始状态。我似乎记得vector实际上被指定为空,许多程序员都认为是正确与否。

答案 1 :(得分:2)

  

移动构造函数将对象置于有效但未指定状态的上下文是什么,它是否适用于std :: vector :: push_back可能存在的内存不足情况?

不,它不适用。有足够的内存来执行push_back不是一个先决条件。当系统没有更多内存时,可以调用push_back(通常,程序无法事先知道分配是否成功),如果内存不足则会出现异常。这只是push_back的正常行为,而不是违反前提条件。

  

特别是,如果std :: vector :: push_back在移动之前有效,是否可以保证工作(忽略其他进程使用内存等问题)?

尝试push_back是合法的,但不保证能够正常工作。移动后,矢量的存储可能已移至移动目标,push_back可能导致重新分配,但可能会失败并抛出bad_alloc

但是忽略分配失败,push_back将成功,正如霍华德的评论所说,现在你的向量具有未知数量的元素加上一个未知数量。有效但不是很有用。