【问题标题】:std::vector and std::string reallocation strategystd::vector 和 std::string 重新分配策略
【发布时间】:2014-01-25 15:17:16
【问题描述】:

在 GCC 的实现中,std::string 和 std::vector 的重新分配策略是什么?

我对所采用的特定策略感兴趣:当我将项目附加到向量(或将字符附加到字符串)时,它可能会超过保留的大小,然后会发生重新分配,但是作为函数的新大小是多少旧的?在删除元素的情况下,实际重新分配和释放内存的阈值是多少(新大小又是多少)?

其他编译器的答案也将不胜感激。

【问题讨论】:

  • 为了澄清这个问题(根据@Paul 的解决方案),我对如何避免重新分配不感兴趣,而是学习实施使用的策略。

标签: c++ gcc stl


【解决方案1】:

查看bits/stl_vector.h 中的函数_M_check_len。它包含:

const size_type __len = size() + std::max(size(), __n);

因此,添加 n 个元素时的基本策略是将大小加倍或增加 n,以最大者为准。 pop_back 永远不会解除分配。 libc++ (LLVM) 完全一样。

阅读代码是了解字符串、释放等策略的唯一方法。

【讨论】:

【解决方案2】:

vectorstring 都保证push_back 的复杂度是“摊销常数”,这意味着调用push_back 所花费的时间n 次除以n 变大时,n 以常数为界。实现这一点的唯一方法是重新分配以几何方式增加大小,即使新容量成为旧容量的固定倍数。这样你只会有非常“少”的重新分配。

实现中的典型增长因子是 2 或 1.5,但任何严格大于 1 的数字都可以。

不过,这不会与 reserve 交互。如果您在每次回送之前致电reserve(size() + 1),您每次都可能得到重新分配。

【讨论】:

    【解决方案3】:

    reserve 究竟是如何工作的,所有的赌注都没有了。你可以这样使用它:

    std::vector<T> myV;
    myV.reserve(<space known to be needed>);
    

    所以你知道reserve 不会被调用(也不会执行任何重新分配)直到之后该空间被超出。

    【讨论】:

      【解决方案4】:

      std::vector 具有方法大小和容量。编写一个确定内存分配方式的简单程序应该不会太难。策略可能会随着每次实施而变化,甚至会因版本而异。

      我见过的一个策略是使用递增增量,这是一种自适应策略:给饥饿的人更多的食物,以避免频繁的数据洗牌。但增加的因素有待讨论。一个简单的复制可能增长太快。

      稍后

      我自己很好奇,我写了那个程序。这是输出(g++ 4.3.3):

      capacity from 0 to 1 increased by 1 at size 1
      capacity from 1 to 2 increased by 1 at size 2
      capacity from 2 to 4 increased by 2 at size 3
      capacity from 4 to 8 increased by 4 at size 5
      capacity from 8 to 16 increased by 8 at size 9
      capacity from 16 to 32 increased by 16 at size 17
      capacity from 32 to 64 increased by 32 at size 33
      capacity from 64 to 128 increased by 64 at size 65
      capacity from 128 to 256 increased by 128 at size 129
      capacity from 256 to 512 increased by 256 at size 257
      capacity from 512 to 1024 increased by 512 at size 513
      capacity from 1024 to 2048 increased by 1024 at size 1025
      capacity from 2048 to 4096 increased by 2048 at size 2049
      capacity from 4096 to 8192 increased by 4096 at size 4097
      capacity from 8192 to 16384 increased by 8192 at size 8193
      capacity from 16384 to 32768 increased by 16384 at size 16385
      capacity from 32768 to 65536 increased by 32768 at size 32769
      capacity from 65536 to 131072 increased by 65536 at size 65537
      capacity from 131072 to 262144 increased by 131072 at size 131073
      capacity from 262144 to 524288 increased by 262144 at size 262145
      capacity from 524288 to 1048576 increased by 524288 at size 524289
      

      在构造函数中使用初始分配会导致相同的进程,使用初始值而不是 1。

      【讨论】:

        猜你喜欢
        • 2020-09-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-20
        相关资源
        最近更新 更多