在内部,向量的向量如何扩展? C++
Internally, how does a vector of vectors expand? c++
假设我有这样一个程序:
#include<vector>
int main()
{
std::vector< std::vector < int > > vexample(2);
vexample[1].push_back(0);
vexample[0].push_back(0);
}
在第一行,我初始化了一个包含 2 个零长度整数向量的向量。在第二行,我 push_back() 一个 int 到第二个向量中,导致 vexample[1] 调整大小。
当第一个 vexample[0] 由于 pushback() 调整大小时,vexample(向量中的向量)在下一行发生了什么? vexample[2] 是否向前移动了 4 个字节?
每个向量都包含一个指针,指向在 free-store 上分配的内存以保存其项目。所以 vexample
什么也没有发生。 vexample[0]
可能会重新设置其指针的数据,vexample[1]
会保留在原处,直到您更改 IT。 None 个 vexample
个元素变大或变小。
我认为你对向量的内部工作方式有误解。
一个向量通常只在内部(即在栈上)存储 3 个东西:
- 它的大小
- 它的容量(即它在不调整大小的情况下可以增长到的最大大小)
- 指向堆上存储实际数据的数组的指针
(通常,出于性能原因,实现使用 3 个指针来代替,但在概念上是相同的)。
这意味着可以增长或收缩的部分存储在堆上。如果你把 push_back
个元素变成 vexample[1]
你会让它增长,因此大小、容量和指针的值会根据需要更新,但这并不意味着它们需要更多 space on the 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 away" 其他任何东西,因为虽然确实必须存储相同向量的元素连续地,对应于不同向量的内存区域没有这样的要求。因此,当您将 push_back
元素放入 vexample[1]
并强制其增长时,vexample[0]
或 vexample
或 vexample[2]
(如果存在)都不需要做任何事情。特别是,vexample[2]
不需要移动,因为 vexample[1]
增长:相反,如果 vexample[1]
增长,那么 vexample[1]
必须为自己找到一个新的位置。
如果矢量的 variable-size 部分保存在堆栈中,所有这些都将成为问题,堆栈中的所有内容都彼此相邻存储。但这正是你只存储一个指向堆的指针的原因,所有的增长和收缩都发生在那里,它不会造成任何伤害。
假设我有这样一个程序:
#include<vector>
int main()
{
std::vector< std::vector < int > > vexample(2);
vexample[1].push_back(0);
vexample[0].push_back(0);
}
在第一行,我初始化了一个包含 2 个零长度整数向量的向量。在第二行,我 push_back() 一个 int 到第二个向量中,导致 vexample[1] 调整大小。
当第一个 vexample[0] 由于 pushback() 调整大小时,vexample(向量中的向量)在下一行发生了什么? vexample[2] 是否向前移动了 4 个字节?
每个向量都包含一个指针,指向在 free-store 上分配的内存以保存其项目。所以 vexample
什么也没有发生。 vexample[0]
可能会重新设置其指针的数据,vexample[1]
会保留在原处,直到您更改 IT。 None 个 vexample
个元素变大或变小。
我认为你对向量的内部工作方式有误解。
一个向量通常只在内部(即在栈上)存储 3 个东西:
- 它的大小
- 它的容量(即它在不调整大小的情况下可以增长到的最大大小)
- 指向堆上存储实际数据的数组的指针
(通常,出于性能原因,实现使用 3 个指针来代替,但在概念上是相同的)。
这意味着可以增长或收缩的部分存储在堆上。如果你把 push_back
个元素变成 vexample[1]
你会让它增长,因此大小、容量和指针的值会根据需要更新,但这并不意味着它们需要更多 space on the 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 away" 其他任何东西,因为虽然确实必须存储相同向量的元素连续地,对应于不同向量的内存区域没有这样的要求。因此,当您将 push_back
元素放入 vexample[1]
并强制其增长时,vexample[0]
或 vexample
或 vexample[2]
(如果存在)都不需要做任何事情。特别是,vexample[2]
不需要移动,因为 vexample[1]
增长:相反,如果 vexample[1]
增长,那么 vexample[1]
必须为自己找到一个新的位置。
如果矢量的 variable-size 部分保存在堆栈中,所有这些都将成为问题,堆栈中的所有内容都彼此相邻存储。但这正是你只存储一个指向堆的指针的原因,所有的增长和收缩都发生在那里,它不会造成任何伤害。