当第一个向量重新分配时,另一个向量中的 std::向量会重新分配吗?
Will std::vectors inside another vector reallocate when the first vector reallocates?
我有一个向量std::vector<std::vector<ContactPairs>> m_contactPairs;
如果我调用 m_contactPairs.push_back()
或任何其他将调整最外层向量大小的函数,该向量内的元素是否必须重新分配(本例中的内部元素std::vector<ContactPairs>
),还是内部向量只是做一个浅拷贝并继续指向他们已经拥有的相同内存?
我使用的是Visual Studio 2010,它是C++11之前的,但具有一些扩展功能
简短回答:这取决于您使用的标准和库实现:
- 在 C++98 和 C++03 中没有移动,因此所有内容都将被深度复制,包括重新分配。
- 在 C++11 和 C++14 中,将有一个包含重新分配的深层副本,或者,如果实现提供了
std::vector<ContactPairs>
的移动构造函数noexcept
。 - 在即将到来的 C++17 中,内部向量将被移动,并且不执行深度复制。
如下:
内部向量类型
std::vector<ContactPairs>
有一个移动构造函数,该构造函数根据即将推出的 C++17 标准(截至 N4296)noexcept
,而不是根据 C++11 和 C++14 标准第 [vector.modifiers] 节noexcept
。你也可以在这里找到这个。然而,即使是符合C++11和C++14的实现也可以指定noexcept
,因为实现可以提供比标准规定的更强的保证(见C++标准17.6.5.12)。不过,许多实施还没有这样做。std::vector<T>::push_back()
的实现需要保证强大的异常安全性,即如果它抛出,则没有副作用。(请参阅C++标准第 [container.requirements.general] §10 或 §11 一节或此处。如果调用
push_back()
的矢量的新大小超过其容量,则需要为新点分配内存,并且需要将元素复制或移动到新点。如果移动外部向量的元素可能失败(无noexcept
),则需要复制元素才能实现强异常保证。在这种情况下,内部向量的每个副本都需要额外的分配。但是,如果移动是noexcept
,那么整个移动循环不能抛出,并且可以安全地用于实现强异常保证。
在noexcept
保证的情况下实施std::vector<T>
搬迁建设,对std::vector
来说似乎是一件微不足道的事情。我怀疑,为了一致性,标准委员会可能犹豫是否要把这个保证放到标准中:对于其他基于节点的容器,拥有哨兵节点可能是有益的,即使对于默认构造也需要分配。由于移自容器在移动后需要有效,因此可能需要为可能引发的std::list
移动进行分配。因此,对于std::list
和其他基于节点的标准容器类型的移动构造函数,没有noexcept
保证。
在 C++03 中,std::vector
重新分配将复制("深层复制")每个元素。 这意味着对于您的情况,每个向量都会被复制。
在 C++11 或更高版本中,仅当元素具有noexcept
的移动构造函数时,std::vector
重新分配才会移动每个元素。
Visual Studio 2010缺乏noexcept
支持,因此您仍然可以获得深层副本。
- 用字符串的向量分配字符串向量
- 如何将向量分配给参考变量?
- 如何将C++向量分配给非表全局变量
- 向量分配上的 C++ 分割错误
- 如何将int分解为数字并以相同的顺序为向量分配数字
- 将向量分配给一个元素
- 将向量分配给向量向量的向量时,向量是范围的
- 带有Valgrind的C 的向量分配中的内存泄漏
- 将向量分配给另一个
- 为向量分配内存
- 为结构的整个向量分配结构的元素
- 将向量分配给结构的向量字段
- C++对象的向量:分配对象
- C++:通过从映射向量分配映射实例来填充映射的映射
- 将儿童的向量分配给祖父母的向量
- 使用 std::向量分配的类比 LOT 的指针分配慢
- C++ 向量分配问题
- 为什么向量分配会改变分配的向量
- 在C++中初始化向量时,你能给向量分配一个大的内存块吗
- 向量分配中的问题