制作 std::矢量容量>=N 和大小=0 的最佳方法是什么?

the best way to make a std::vector capacity>=N and size=0?

本文关键字:最佳 是什么 方法 容量 gt 制作 std      更新时间:2023-10-16

给定一个大小和容量可以任意的std::vector,将其大小更改为 0 并将容量更改为至少 N(给定数字(的最佳实践是什么?

我的直接想法是:

void f(vector<int> &t, int N)
{
t.clear();
t.reserve(N);
}

但我注意到

不能保证会发生重新分配,并且向量容量为 不保证会改变(当调用 std::vector::clear 时(。

所以我想知道当源容量大于给定的 N 时如何避免重新分配?

将其

大小更改为 0 并将容量更改为 N(给定数字(的最佳实践是什么?我的直接想法是:...

你的直接想法是正确的,也是最简单的选择。虽然是迂腐的,reserve将容量更改为大于或等于给定的数字;不能保证相等(但是,如果以前的容量较小,我测试过的所有实现都会精确地分配给定的数量(。

所以我想知道当源容量大于给定的 N 时如何避免重新分配?

通过使用标准库实现,该实现已选择在调用clear时不释放内存(即任何符合标准标准的实现,如此处的答案所示(。


另一种保证方法(尽管这似乎没有必要,因为尽管 cplusplus.com 的措辞很弱,但应该保证上述内容(没有重新分配(在N > t.capacity()的情况下(:由于向量包含简单的整数,并且您似乎知道将有多少元素(因为您知道要保留(,您可以简单地调用t.resize(N)(在大小较大的情况下删除多余的元素(,而无需清除向量, 然后继续覆盖现有元素,而不是推送新元素。

当然,这意味着您将无法观察到已覆盖的元素数量,因此此方法不适用于所有用例。如果您只是想用一个简单的循环填充向量,那很好。

如果新大小可能大于旧大小,并且您希望不要过度分配,则可能需要在调整大小之前进行保留。这是因为大多数实现在保留时分配确切的数量(如我所提到的(,但在调整大小时使用乘法策略(据我所知,这些行为都不能保证,但我使用的实现与这种行为一致(。

最好的方法可能是你当前的代码。

不幸的是,该标准允许实现具有容量只能增长的容器。在这种情况下,您的代码将仅保证容量至少为N。如果初始容量小于 N,则会发生重新分配,如果容量大于 N,则不会发生任何情况。这一点由标准保证,因为 C++17 的草案 4659 在 [vector.capacity] 上说(强调我的(:


void reserve(size_type n);......
3 效果:通知向量计划的大小更改的指令,以便它可以管理存储 相应地分配。在 reserve(( 之后,capacity(( 大于或等于 reserve 的参数,如果 发生重新分配;否则等于 capacity(( 的先前值。发生重新分配 此时,当且仅当当前容量小于 reserve(( 的参数时。


void shrink_to_fit();......
8 效果:shrink_to_fit 是一个将 capacity(( 减少到 size(( 的非约束性请求。[ 注:请求 不具有约束力,允许为特定于实现的优化留有余地。—尾注 ] 它没有 增加容量((,但可能会通过导致重新分配来减少容量((。

您无法保证容量正好为 N。相反,您的代码保证,如果初始容量大于 N in,则保持不变,并且不会发生重新分配。

编辑:至少自 C++11 年以来,此行为是稳定的(草案 n3337(

注意:这个答案回答了以下问题:

制作 std::矢量容量=N 和大小=0 的最佳方法是什么?

将其大小更改为 0 并将容量更改为 N(给定数字(的最佳做法是什么?

在此答案发布后,添加了对">= N"的更改并添加了避免重新分配的要求。


该标准没有提供任何保证的方式来实现这一目标。但你最好的机会是:

t.clear();
t.shrink_to_fit();
t.reserve(N);

建议进行第二次调用以减小容量以匹配当前大小(此时将0(。

同样由实现自行决定的可能有效也可能无效的替代方法是:

t.swap( std::vector<int>{} );
t.reserve(N);
相关文章: