std::vector/编程书籍神话的默认大小

Default size of std::vector / Programming books myth?

本文关键字:神话 默认大小 编程 vector std      更新时间:2023-10-16

在一本名为";C++für C程序设计器";(C++适用于C程序员,duh!(作为参考,我在关于STL的章节中找到了以下部分(我马上为你们翻译(:

大多数STL实现在内存管理方面都很慷慨。对于实例,向量的分配大多以1kb的块来完成。如果分配了几个向量,剪切并不重要,但如果创建了10到100个向量,剪切就会重要。

我找不到任何消息来源证实这一点。我知道这取决于实现,但我找不到任何东西来证实哪怕是一个平台。Cplusplus.com仅声明:

[…]

因此,与阵列相比,矢量消耗更多的内存,以换取管理存储和以高效方式动态增长的能力。

到目前为止我试过什么

我写了一个利用OSX特定malloc_size((函数的C++程序,但我从未使用过它,我很确定我做错了。如果我做了一些类似的事情:

std::vector<int>* i = new std::vector<int>;
std::cout << malloc_size(i) << std::endl;

我只是告诉我32,这很可能是一个整数的大小,因此证明了作者的部分错误,但我自己的努力并没有说服我。

有人更了解或了解资源吗?提前谢谢。

谨致问候,Carson

您的代码无法测量您想要测量的内容。vector结构本身通常相当小。它基本上包含一些跟踪分配的内存所必需的字段和指向该内存的指针。你想要测量的是不同的。

------        -------------------
| i  |------> | A few fields    |
------        | (e.g., size and |
              |  capacity)      |         -------------------
              |-----------------|         | Space allocated |
              |   pointer       |-------> | for elements    |
              -------------------         -------------------
                 ^                            ^
               What your code               What you want to
               measures                     measure

您可能可以为vector提供一个自定义分配器,用于跟踪和报告请求的分配大小。我的计算机上的GCC 4.8.1实现没有为默认构建的向量分配内存(因为它没有元素(,并在注释中指出的每个增长实现上使用双倍大小。

矢量对象本身只有几个指针,所以您显示的32字节大小并不奇怪,而且不会随着时间的推移而改变。

我相信这本书的文本是指为向量的内容分配的存储空间。当您将项目添加到向量中时,它会分配空间来存储它们,但该空间不会反映在malloc_size中。

通过调用向量的capacity()方法,可以计算出向量分配了多少空间。这会告诉你它能装多少件物品。如果需要以字节为单位的大小,则可以将容量乘以元素类型的大小。

引用的文本谈到了大约1 KB的块。旧的动态容器在需要增长时使用线性方案。但是标准对std::vector的运行时复杂性要求不允许这种方法。相反,矢量必须按其当前大小的某个百分比增长。

许多实现使用100%。因此,如果一个向量目前有10个项目的空间,并且需要增长,它将调整多达20个项目的大小。如果它需要进一步增长,它将调整多达40个项目的大小,以此类推。因此,在最坏的情况下,你可能会得到一个向量,它分配的空间几乎是实际需要的两倍。有些实现使用50%,这仍然满足运行时复杂性要求,而不会增长得那么快或"浪费"那么多空间。(使用小于100%的因子至少还有一个其他优点,但与本讨论无关。(

在具有虚拟内存的现代计算机上,任何一种方法通常都很好——性能将比未使用的内存更重要。如果你在一个资源有限的嵌入式系统上,你可能想要进行更直接的控制。有一些技巧,如复制和交换,可以将具有多余容量的向量修剪到接近实际需要的大小。

这本书在很多方面都不正确。std::vector根据几何级数增长,因此将始终填充一定的百分比(除非使用erase元素(。剪辑可能会相加,但一般来说,它与实际使用的内存成正比。50-65%是实际使用的馏分的典型最坏情况下限。

这与实现无关。需要几何级数来确保push_back占用O(1(的摊销时间。线性增长将导致O(N(的摊销时间(或O(N^2(到push_back的N值序列(。

实现可以为非空的vector决定一个不可忽略的最小大小,但没有充分的理由这样做,因为小的是常见的。同样,默认的初始化向量总是被实现为根本不保留动态内存。

您不需要malloc_size来了解保留了多少内存。只需使用v.capacity() * sizeof( elem_type )