【问题标题】:Will a std::vector's capacity ever be reduced?std::vector 的容量会减少吗?
【发布时间】:2018-10-13 09:19:27
【问题描述】:

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 会减少其容量吗?
那么是否有一些条件可以触发其容量的减少呢?

【问题讨论】:

  • 只是我的,但如果一个向量到达某个size()。那么有理由假设它会再次达到这个目标。而减少capacity 只是浪费时间。

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


【解决方案1】:

所以我认为当一个向量的容量远大于它的大小时,它应该减少它的容量。

首先,标准必须明确“容量远大于其大小”的含义。这将限制实现当前对重新分配策略的选择。

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

目前,擦除状态

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

第三,向量很可能再次达到其容量的高水位线,因为它很可能会长时间保持较小。

对于一些有效的场景,您会使得使用情况变得更糟,因为释放大量分配的可疑好处。现代虚拟内存系统可以很好地处理旧的分配,这些分配的时间严格超过了必要的时间。

那么是否有一些条件可以触发它的容量减少呢?

是的,shrink_to_fit 是一个明确的请求来做你想做的事。如果您确实希望它重新分配到更小的尺寸,您可以提出要求。其他会受到小蛇伤害的用途不受影响。

【讨论】:

    【解决方案2】:

    如果您的实现中的 std::vector::shrink_to_fit() 没有达到您想要的效果(因为它只是发出 非绑定 请求以减少向量的容量),您可以考虑应用 @987654321 @在你的矢量上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);
    

    这个习惯用法包括创建一个临时向量对象,该对象由原始向量v的元素组成,然后交换这个生成的临时与原始向量矢量v

    应用此成语交换生成的临时向量和v 的容量。 如果生成的临时向量的容量低于原始向量v,这将导致v 的容量更低。如果v.size() 远低于v.capacity(),则可能会出现这种情况。

    【讨论】:

      【解决方案3】:

      取决于在哪些操作下。如果你包括所有这些,那么是的。

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

      备注shrink_to_fit 是一个将capacity() 减少为size() 的非约束性请求。 [ 注意:该请求是非绑定的,以允许进行特定于实现的优化。 — 尾注 ] ...

      和 [vector.capacity]p10 (swap):

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

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


      关于以下内容的快速说明:

      所以我认为当一个向量的容量远大于它的大小时,它应该减少它的容量。我编写了以下代码来检查我的假设:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-03
        • 2012-03-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多