std :: vector的容量会降低吗?

时间:2018-10-13 09:19:28

标签: c++ vector std stdvector c++-standard-library

C++14 final working draftstd::vector发表以下评论:

  

存储管理是自动处理的,尽管可以提供一些提示来提高效率。

cppreference说:

  

向量的存储是自动处理的,可以根据需要进行扩展和收缩。

Wikipedia entry for Dynamic array说:

  

C ++的std::vector和Rust的std::vec::Vec是动态数组的实现

因此,我认为向量的容量远大于其大小时,应该自动减少其容量。我编写了以下代码来检查我的假设:

#include <iostream>
#include <vector>

using namespace std;

int main() {
  vector<int> v = {};

  cout << "initialization" << endl;
  cout << "  capacity: " << v.capacity() << endl;
  cout << "  size: " << v.size() << endl;

  for (int i = 1; i <= 10000; i++) 
    v.push_back(i);

  cout << "after inserting a lot of elements" << endl;
  cout << "  capacity: " << v.capacity() << endl;
  cout << "  size: " << v.size() << endl;

  v.erase(v.begin() + 1, v.begin() + 10000);
  cout << "after erasing a lot of elements" << endl;
  cout << "  capacity: " << v.capacity() << endl;
  cout << "  size: " << v.size() << endl;

  v.push_back(9);

  cout << "after inserting another element" << endl;
  cout << "  capacity: " << v.capacity() << endl;
  cout << "  size: " << v.size() << endl;
}

我用g++ -std=c++14 code.cc来编译代码。运行结果a.out会产生以下输出。我正在使用macOS Mojave。

initialization
  capacity: 0
  size: 0
after inserting a lot of elements
  capacity: 16384
  size: 10000
after erasing a lot of elements
  capacity: 16384
  size: 1
after inserting another element
  capacity: 16384
  size: 2

因此,std::vector似乎并没有减少容量,即使其容量远大于其大小。

std::vector会减少容量吗?
那么是否有条件触发其容量减少?

3 个答案:

答案 0 :(得分:5)

  

因此,我认为向量的容量应远大于其大小时,应减少其容量。

首先,该标准必须规定“容量远大于容量”的含义。这将限制当前实现方案对重新分配策略的选择。

第二,如果减少容量,则需要重新分配和移动所有剩余的元素。这意味着所有迭代器可能会由于擦除而失效,从而限制了安全使用。

当前,擦除状态

  

使擦除点或擦除点之后的迭代器和引用无效,包括end()迭代器。

第三,向量很可能再次达到其容量的高水位标记,并且可能长时间保持不变。

在许多有效情况下,由于释放大量分配的可疑好处,您的使用情况会更糟。现代虚拟内存系统可以很好地处理旧分配,其保留时间比必要时间更长。

  

那么有什么条件可以触发其容量的减少?

是的,shrink_to_fit是执行明确要求的明确要求。如果您这样做希望将其重新分配为较小的大小,则可以提出要求。可能会引起碎裂的其他用法不受影响。

答案 1 :(得分:2)

如果您的实现中的std::vector::shrink_to_fit()并没有达到您想要的效果(因为它只是发出了 non-binding 请求以减少向量的容量),则可以考虑应用swap-to-fit idiom在向量v上:

std::vector<int> v;

// ...

{
   std::vector<int> tmp(v); // create a copy of vector v
   tmp.swap(v);
   // vector tmp goes out of scope --> tmp is destroyed
}

或者只是单线:

std::vector<int>(v).swap(v);

此成语包括创建一个 temporary 向量对象,该对象由原始向量v的元素组成,然后 swap 将该临时对象与原始向量v

应用这个惯用法可以交换所得的临时向量和v的容量。 如果生成的临时变量的容量小于原始向量v的容量,这将导致v的容量较低。如果v.size()v.capacity()低得多,可能就是这种情况。

答案 2 :(得分:1)

取决于执行哪个操作。如果包括所有这些,那么是的。

请参见[vector.capacity] p9(shrink_to_fit):

  

备注shrink_to_fit是一种非约束性请求,用于将capacity()减少为size()。 [注意:该请求是非绑定的,以便为实现特定的优化留出余地。 — 尾注] ...

和[vector.capacity] p10(swap):

  

效果:将capacity()的内容和*thisx的内容和内容交换。

换句话说,使用shrink_to_fit()可以减少容量。使用swap(),只要您能够用更少的vector创建另一个capacity(),就可以保证减少您的 capacity() swap()它们(但请注意,“原始”容量(即现在是另一个对象的容量)本身并未降低)。


有关以下内容的快速注释:

  

因此,我认为向量的容量应远大于其大小时,应减少其容量。我编写了以下代码来检查我的假设:

为了减少capacity(),实现将需要(通常)分配内存(并移动/复制元素并取消分配原始存储),这是一个非常昂贵的操作,在擦除元素时没人希望。

最重要的是,如果您的程序然后再次到达其新的capacity()(很可能是因为您之前已经这样做过),则必须再次重复该过程。