当第一个向量重新分配时,另一个向量内的std :: vectors会重新分配吗?

时间:2015-01-27 15:33:06

标签: c++ vector stl

我有一个向量std::vector<std::vector<ContactPairs>> m_contactPairs;

如果我调用m_contactPairs.push_back()或任何其他将调整最外层向量的函数,那么该向量内的元素是否必须重新分配(在这种情况下内部元素为std::vector<ContactPairs>),或者内部元素向量只做一个浅拷贝,并指向他们已经拥有的相同内存?

我使用的是Visual Studio 2010,它是先前的C ++ 11,但有一些功能作为扩展

2 个答案:

答案 0 :(得分:15)

简短回答:这取决于您使用的标准和库实现:

  • 在C ++ 98和C ++ 03中没有任何移动,因此一切都将被深深复制,包括重新分配。
  • 在C ++ 11和C ++ 14中,将有一个包含重新分配的深层副本,或者,如果实现在noexcept的移动构造函数上提供std::vector<ContactPairs>
  • 在即将发布的C ++ 17中,内部向量将被移动,不会执行深层复制。

这就是推理:

  1. 根据即将推出的C ++ 17标准(截至N4296)和 {内部向量类型std::vector<ContactPairs>有一个移动构造函数noexcept {1}}根据C ++ 11和C ++ 14标准,[vector.modifiers]部分。你也可以找到这个here。但是,即使符合C ++ 11和C ++ 14的实现也可以指定noexcept,因为实现可以提供比标准规定的更强的保证(参见C ++标准17.6.5.12)。但是,许多实现方法并没有这样做。

  2. noexcept的实施需要保证strong exception safety,i。即如果它抛出没有副作用。 (参见C ++标准,[container.requirements.general]§10或§11或here部分。)

  3. 如果您调用std::vector<T>::push_back()的向量的新大小超过其容量,则需要为新位置分配内存,并且需要复制元素或将其移动到新位置。如果移动外部向量的元素可能失败(无push_back()),则需要复制元素以实现强异常保证。在这种情况下,内部向量的每个副本都需要额外的分配。但是,如果移动是noexcept,则整个移动循环不能抛出并且可以安全地用于实现强异常保证。

  4. 使用noexcept保证实施std::vector<T>移动构建似乎对noexcept来说是微不足道的。我怀疑,标准委员会可能会犹豫是否将此保证放入标准中以保持一致性:对于其他基于节点的容器,具有标记节点可能是有益的,即使对于默认构造也需要分配。由于移动后的容器需要在移动后有效,因此可能会有一个std::vector移动所需的分配,例如可能抛出。因此,std::list的移动构造函数和其他基于节点的标准容器类型没有noexcept保证。

答案 1 :(得分:9)

在C ++ 03中,std::vector重新分配将复制(“深层复制”)每个元素。这意味着,对于您的情况,每个向量都将被复制。

在C ++ 11或更高版本中,std::vector重新分配将移动每个元素仅当元素具有{{1}的移动构造函数时}。

Visual Studio 2010缺少noexcept支持,因此您仍然可以获得深层副本。

相关问题