假设我有一个这样的程序:
#include<vector>
int main()
{
std::vector< std::vector < int > > vexample(2);
vexample[1].push_back(0);
vexample[0].push_back(0);
}
在第一行,我初始化一个包含2个零长度向量的int的向量。在第二行,我将一个int push_back()放到第二个向量中,导致vexample [1]调整大小。
当第一个vexample [0]由于pushback()调整大小时,下一行的矢量矢量会发生什么变化? vexample [2]向前移动了4个字节吗?
答案 0 :(得分:2)
每个向量都包含一个指向免费存储分配的内存的指针,用于保存其项目。所以vexample
没有任何事情发生。 vexample[0]
可能重置其指针的数据vexample[1]
保持原样,直到您更改IT为止。 vexample
个元素都不会变大或变小。
答案 1 :(得分:2)
我认为你对矢量在内部的运作方式存在误解。
向量通常在内部只存储3个东西(即在堆栈上):
(通常,出于性能原因,实现使用3个指针,但从概念上讲它是相同的。)
这意味着可以增长或缩小的部分存储在堆上。如果将push_back
元素放入vexample[1]
,您将使其增长,因此大小,容量和指针的值将根据需要进行更新,但这并不意味着它们需要更多空间stack:它仍然是3个固定大小的变量,其中“fixed”表示它是在编译时确定的。
如果我们假设size
和capacity
被实现为int
并且每个需要4个字节,并且指针需要8个字节,那么你需要一个向量需要4 + 4 + 8 =堆栈上的16个字节,无论它包含的元素的类型和数量,以及堆上的capacity * sizeof(T)
个字节。堆上使用的内存量可能不同,而堆栈上的内存不能。
在您的情况下,vexample
的元素也是向量,因此每个元素需要16个字节,加上分配容量的大小。所以,内存布局是这样的:
vexample
在堆栈上占用16个字节。在这16个字节中,8个是指向堆区域的指针,其中有2个元素的数组,每个元素需要16个字节,因此它是一个32字节的连续块:前16个用于vexample[0]
,最后16个是vexample[1]
。它们中的每一个都包含一个指向int
数组的指针。
当这些向量中的任何一个增长时,堆上的数据可能需要重新分配,但这并不会“推开”其他任何东西,因为虽然确实必须连续存储相同向量的元素,对应于不同向量的存储区域没有这样的要求。因此,当您将push_back
元素加入vexample[1]
并强制它成长时,vexample[0]
,vexample
和vexample[2]
(如果存在)都不需要做任何事情。特别是,vexample[2]
不需要移动,因为vexample[1]
增长:相反,如果vexample[1]
增长,那么vexample[1]
必须为自己找到一个新的位置。
如果向量的可变大小部分保存在堆栈中,并且所有内容彼此相邻存储,则所有这些都将成为问题。但这正是你只存储一个指向堆的指针的原因,并且所有增长和收缩都发生在那里,它不会造成任何伤害。