我有一个向量std::vector<std::vector<ContactPairs>> m_contactPairs;
如果我调用m_contactPairs.push_back()
或任何其他将调整最外层向量的函数,那么该向量内的元素是否必须重新分配(在这种情况下内部元素为std::vector<ContactPairs>
),或者内部元素向量只做一个浅拷贝,并指向他们已经拥有的相同内存?
我使用的是Visual Studio 2010,它是先前的C ++ 11,但有一些功能作为扩展
答案 0 :(得分:15)
简短回答:这取决于您使用的标准和库实现:
noexcept
的移动构造函数上提供std::vector<ContactPairs>
。 这就是推理:
根据即将推出的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)。但是,许多实现方法并没有这样做。
noexcept
的实施需要保证strong exception safety,i。即如果它抛出没有副作用。 (参见C ++标准,[container.requirements.general]§10或§11或here部分。)
如果您调用std::vector<T>::push_back()
的向量的新大小超过其容量,则需要为新位置分配内存,并且需要复制元素或将其移动到新位置。如果移动外部向量的元素可能失败(无push_back()
),则需要复制元素以实现强异常保证。在这种情况下,内部向量的每个副本都需要额外的分配。但是,如果移动是noexcept
,则整个移动循环不能抛出并且可以安全地用于实现强异常保证。
使用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
支持,因此您仍然可以获得深层副本。