【问题标题】:How to shrink-to-fit an std::vector in a memory-efficient way?如何以节省内存的方式缩小以适应 std::vector?
【发布时间】:2011-02-11 08:08:43
【问题描述】:

我想“缩小以适应”std::vector,以将其容量减少到其确切大小,从而释放额外的内存。标准技巧似乎是here 描述的技巧:

template< typename T, class Allocator >
void shrink_capacity(std::vector<T,Allocator>& v)
{
   std::vector<T,Allocator>(v.begin(),v.end()).swap(v);
}

shrink-to-fit 的全部意义在于节省内存,但这种方法不是先创建一个深拷贝,然后交换实例吗?所以在某些时候——当副本被构建时——内存使用量翻了一番?

如果是这种情况,是否有更适合内存的收缩以适应的方法? (在我的情况下,向量真的很大,我不能随时在内存中同时拥有原始和副本。)

【问题讨论】:

  • 不是真的,他想在交换发生的同时防止内存中两个项目的临时副本。
  • 实际上,另一个问题也是如此(避免复制)。感谢您的链接。
  • 双端队列能否为您提供更接近您想要的机制?在填充时,它们的开销通常比向量少,因此最终的收缩步骤并不那么重要。

标签: c++ stl vector capacity


【解决方案1】:

好吧,如果你想调整数组的大小,你会怎么做?您必须创建一个新值并复制所有值 - 无论是单独还是使用 memcpy 或其他任何值。在 C 或 C++ 中,您无法真正调整数组的大小。

std::vector 几乎可以保证使用数组来实现其存储(IIRC,标准不保证它是数组,但数组是唯一可以满足 API 的各种要求的东西,例如每个操作必须有多高效;因此,实际上,即使该保证不明确,也可以保证)。由于它是使用数组实现的,并且您无法在不复制的情况下调整数组的大小,因此您无法在不复制的情况下调整向量的大小。

理论上,您可以拥有一个 shrink_capacity() 函数,它隐藏了您必须暂时或多或少地将其大小要求翻倍的事实,但由于 std::vector 目前没有这样的函数,您必须实际制作显式副本。交换技巧只是一个很好的方法。

如果在这种情况下你真的关心内存,你可以做的是使用指针(或智能指针)而不是让向量直接保存对象。这可能不是完全可取的,但它会减少您的内存需求。

【讨论】:

  • 为什么 stl::Vector 不能简单地告诉 malloc(或 new)它不再需要从最终条目到保留大小的内存?然后堆分配器可以将其放回空闲列表中 - 无需复制任何内容
  • @Martin 我从未听说过有任何方法可以做到这一点。有 realloc,但由于它不能保证它会返回相同的内存块,所以你会丢失之前数组中的任何内容。如果有办法做到这一点,那么我认为 vector 可以做到这一点,但它目前没有这样的功能,即使它是可能的。
  • 因为大多数内存分配器不是这样工作的;您不能编辑已分配块的边界标记以使其更小,同时将松弛返回到空闲列表。一些奇异的分配器可以做到这一点,但标准库并非旨在依赖它们。
  • 不,我还没有看到任何可以做到这一点 - 我只是指出理论上你不需要复制内存以释放向量末尾的空闲空间。这就是为什么从事 HPC 工作的人通常最终会管理自己的内存。
【解决方案2】:

如果您的新尺寸是原始尺寸的一半,则您可以将新矢量(或者如果矢量无法做到这一点,则使用直接 dynaimc 数组)放置到旧矢量的未使用末端部分。不确定向量是否将信息存储在该内存区域中,因此这将非常骇人听闻。但这是一个想法。

现在我想起来了,一个 memMove() 类型的操作,您将信息从原始中使用的最后一个索引反向复制到原始中未使用区域的后面将保留数据。如果您将此设置为数组的新位置,则可以将其指向新数据将存在于原始内存区域中间的任何位置。就地移动本身。

【讨论】:

    猜你喜欢
    • 2012-03-14
    • 2018-01-27
    • 2012-07-14
    • 2013-10-30
    • 2011-11-24
    • 2010-09-20
    • 2012-04-20
    • 2017-12-13
    相关资源
    最近更新 更多