标准::矢量内存管理

std::vector memory management

本文关键字:管理 内存 标准      更新时间:2023-10-16

我所知,std::vector为它将包含的数据保留了一些内存,如果该内存已满,它将所有数据复制到一个新的更大的内存块中。

例如,如果向量包含 2 个元素,则内存如下所示:

DD--XX-----                  D for vector's data, - for empty, X for other data

如果我添加两个元素,它将变成这样:

DDDDXX-----

但是如果我尝试添加另一个元素,矢量将复制所有元素并释放以前的内存:

----XXDDDDD

我说的对吗?

现在我不希望向量将成员复制到另一个内存块,所以我想知道他什么时候这样做。可能吗?例如,使用在发生这种情况时引发异常的插入函数

是的,您已经正确理解了std::vector的行为。

您可以观察std::capacity - 它为您提供了向量的容量大小,这意味着 - 在下一次重新分配之前,向量可以如何容纳元素。你可以做类似的事情

std::vector< type >::size_type remaining_places = v.capacity() - v.size();

您无法完全阻止这种情况,但您可以随时使用std::vector::reserve更改矢量的容量。

std::vector 的实际规范是这样的

template < class T, class Alloc = allocator<T> > class vector;

其中Alloc 是委派给以分配原始内存的对象的类型。

如果要截获向量执行的大小调整操作,请提供适当定制的分配器。 定制的分配器(一个类,可能是模板化的(将需要允许保留或设置大小的第一个操作,但在后续调整大小尝试时引发异常。 查找模板化std::allocator(以及C++',std::allocator_traits(,了解您的定制分配器必须支持的接口规范。

我说的对吗?

有点。

您的图表使它看起来像矢量重新分配,否则会导致它们运行到其他分配的内存中。那不是真的。矢量在分配的内存不足时重新分配。可能是这个

DD--------
DDD-------
------DDDD

即使没有任何X.

这里的关键是向量执行的预分配。假设向量的容量为 4:

std::vector<int> v;
v.reserve(4);
v.push_back(999);
v.push_back(998);
v.push_back(997);
v.push_back(996);

这可能会导致:

-------XX---------
PPPP---XX---------  set capacity
DPPP---XX---------  add element
DDPP---XX---------  add element
DDDP---XX---------  add element
DDDD---XX---------  add element
DDDD---XX--PPPPPPP  increase capacity; requires new allocation...
DDDD---XX--DDDDPPP  ... and copying of data ...
-------XX--DDDDPPP  ... and de-allocation of the original memory

等等。

现在我不希望向量将成员复制到另一个内存块,所以我想知道他什么时候这样做。可能吗?例如,使用在发生这种情况时引发异常的插入函数

不是真的,但您可以简单地将myVector.size()myVector.capacity()进行比较并自己抛出异常,而不是在两者相等时push _back。这将防止向量本身通过重新分配和复制来处理这种情况。

这听起来有点像您希望矢量尽可能多地就增长,然后在进程内存中的空间不足时抛出。但是,据我所知,没有操作系统级别的支持,当然也没有C++可以访问的内容。(请注意,即使是realloc也可能移动数据。你可以发明一种新型的计算机来做到这一点。从理论上讲,编写池分配器可以做到这一点,但为什么呢?这是大量的工作和令人惊讶的语义——据我所知——基本上没有任何好处。

指定std::vector将元素存储在连续内存中。这意味着,如果附加的值多于连续可用的值,它将在其他地方分配一个更大的连续块,并将值从旧内存块移动到新块。这是正确的行为,您不能或不应该对此采取任何措施。

为了具体回答您的问题,向量将在以下情况下为"满">

vector.size() == vector.capacity()

在此点之后的单个push_backemplace_back(等(将需要在其他地方进行另一次分配,并且您会注意到.capacity()的价值会增加。

std::vector 将至少管理足够的内存来容纳其中的对象。

如果您添加另一个对象导致其空间不足,它将自动增长 - 这是设计使然,无法预防,预测或检测。

如果您的对象是移动感知的,它们将被std::move到新内存中的位置,而不是复制。

矢量中的所有对象都是连续的 - 永远不会有任何间隙(除了对齐要求要求的填充(。

如果从中间删除某些项,则末尾的项将向下移动,以便向量仍包含连续项。

如果你想防止向量增长超过一定大小,你必须为它编码(将向量包装在另一个类中?

您可以使用std::vector::reserve()在矢量中预先保留空间