在comments on Andrzej's move constructor article中,我发布了一个从对象移动的任何成员函数,它没有前置条件。我将示例std::vector::front
作为一个函数,您无法调用移动的std::vector
,因为它具有向量不为空的前提条件。我将std::vector::empty
,std::vector::push_back
和std::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 ]
答案 0 :(得分:3)
如果内存不足,则push_back
会以std::bad_alloc
例外退出,后置条件不适用。 vector
对象保持原始状态。
当向量达到容量时,会发生这种情况:
bad_alloc
异常,请将其传递给用户。什么都没有被修改过。noexcept
,则将元素移动到更大的块中。这必须成功。如果违反noexcept
规范,则实施不必尝试将事情移回(这可能会,也可能会失败。)“有效但未指定”在此上下文中没有任何更深层的含义。用户根本不应该对其中的内容做出假设。但检查它以发现内容,或忽略内容并添加更多内容都很好。
逻辑上,任何对象都应该留空或处于原始状态。我似乎记得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
将成功,正如霍华德的评论所说,现在你的向量具有未知数量的元素加上一个未知数量。有效但不是很有用。