改变C++向量的保留内存

5

我有一个包含1000个节点的向量

 if(count + 1 > m_listItems.capacity())
     m_listItems.reserve(count + 100);

问题是当我准备重新填充时,我也会将其清空。
m_listItems.clear();

容量不会改变。 我使用了resize(1);但似乎没有改变容量。 那么如何更改预留空间?


你的系统内存不足吗?这样保留意味着将n个项目添加到其中需要O(n^2)时间,并且最多使用n+100个对象的空间加上舍入误差。让向量自行扩展会减少代码,需要O(n)时间,并且在大多数实现中最多使用2*n的空间加上舍入。 - Steve Jessop
我的系统内存非常短缺(嵌入式)...这段代码只是我考虑实现的示例。大部分时间我会从“表格”获取1000个项目块,因此按相同频率调整大小是有意义的。清理工作是我主要关注的问题。 - baash05
5个回答

20
vector<Item>(m_listItems).swap(m_listItems);

会再次缩小m_listItemshttp://www.gotw.ca/gotw/054.htm(Herb Sutter)

如果您仍想清除它,请与空向量交换:

vector<Item>().swap(m_listItems);

当然,这样做效率要高得多。(请注意,交换向量基本上只意味着交换两个指针,没有什么耗时的操作。)


2
值得指出的是,虽然swap()非常便宜,但在第一种情况下构造m_listItems的临时副本将需要复制向量中的每个元素。因此,尽管完全清除向量(将容量设置为0)很便宜,但否则缩小它并不便宜。 - jalf
1
jalf确实如此。但是,如果向量本身具有shrink()函数,则需要的序列基本相同。无论如何都需要重新分配:/ - Johannes Schaub - litb
1
但你的观点是正确的,因为在C++1x中,向量可以将它们的元素移动到新位置。我的代码应该简单地看起来像这样:vector<Item>(std::move(m_listItems)).swap(m_listItems); 然后我认为。。。 - Johannes Schaub - litb
我在寻找清晰的解决方案,而不是简单地缩小规模。我正在使用向量作为填充列表的工具。老实说,我以为它是用链表实现的。看来我错了...哦,无论如何,现在速度已经足够快了。 - baash05
@litb:移动它可能不起作用,因为结果将与m_listItems.swap(m_listItems)相同,这是一个无操作。 - dalle
嗯,缓冲区确实会保持相同的维度。我真是太愚蠢了。 - Johannes Schaub - litb

2
你可以像其他人建议的那样交换向量,并且如http://www.gotw.ca/gotw/054.htm所述,但请注意,这是不免费的,因为向量必须分配一个新的、较小的内存块,并复制所有旧内容。(交换操作本质上是免费的,但你正在与一个用原始向量数据副本初始化的临时对象进行交换,这是不免费的)。
如果你事先知道向量的大小,应该一开始就分配正确的大小,这样就不需要重新调整大小了。
std::vector<foo> v(1000); // Create a vector with capacity for 1000 elements

如果您事先不知道容量,那么浪费一点空间有什么关系呢?将每个元素复制到一个新的、更小的向量中需要花费时间(这就是std::vector(v).swap(v)会做的),只为了节省几千字节的内存,这值得吗?
同样地,当您清除向量时,如果您打算重新填充它,将其容量设置为零似乎是一种浪费时间的行为。
编辑:
baash05:如果你有1000000个项目和10兆字节的RAM。你会说减少开销很重要吗?
不。调整向量大小需要更多的内存,暂时地,所以如果你的内存受限,这可能会破坏你的应用程序。(在交换它们之前,你必须将原始向量和临时向量都存储在内存中,因此在那一点上,你最终使用的内存可能是原来的两倍)。之后,你可能会节省一些内存(高达几MB),但这并不重要,因为向量中的多余容量永远不会被访问,所以它会被推到页面文件中,因此首先不会计入你的RAM限制。
如果您有1000000个项目,那么您应该在第一次初始化向量时设置正确的大小。
如果您不能这样做,那么通常最好保留容量不变。特别是因为您已经声明了要重新填充向量,所以一定要重用已经分配的容量,而不是不断地分配、重新分配、复制和释放所有东西。
您有两种可能的情况。要么您知道需要存储多少元素,要么您不知道。如果您知道,那么您可以在第一次创建向量时使用正确的大小,这样您就永远不需要调整其大小,或者您不知道,那么您可能会保留多余的容量,这样当您重新填充向量时,它就不必向上调整大小。

如果你有1000000个项目和10兆字节的RAM,你会说减少开销的数量很重要吗? - baash05

1
你可以尝试这个技巧,来自这里
std::vector< int > v;
// ... fill v with stuff...
std::vector< int >().swap( v );

1
据我所知,你不能将向量重新分配到比它曾经拥有的更低的容量;你只能将其分配得更大。这其中有很好的原因;其中之一是重新分配过程非常计算密集。如果你真的需要一个更小的向量,那么释放旧的向量并创建一个更小的新向量实际上比让向量调整大小更简单。

取决于它如何分配 - 你可以让它超出范围,或者你调用删除。与交换相比,我不认为这是一个好建议。 - Steve Jessop

1

您可以使用swap函数将其与具有所需容量的新向量交换。

vector< int > tmp;
old.swap( tmp );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接