C++中高效的数组重新分配



如何使用符合标准的C++分配器有效地调整分配的数组大小?我知道C++分配程序接口中没有提供重新分配的功能,但C++11版本是否使我们能够更容易地使用它们?假设我有一个类vec,其中定义了一个复制赋值运算符foo& operator=(const foo& x)。如果x.size() > this->size(),我将被迫进入

  1. foo内部存储中的所有元素调用allocater.destroy()
  2. foo.的内部存储器上调用allocater.deallocate()
  3. 重新分配一个有足够空间容纳x.size()元素的新缓冲区
  4. 使用std::uninitialized_copy填充存储

有没有什么方法可以让我更容易地重新分配foo的内部存储,而不必经历所有这些?如果你认为它有用的话,我可以提供一个实际的代码示例,但我觉得这里没有必要。

基于前面的一个问题,我处理可以以合理的效率增长和收缩的大型数组的方法是编写一个类似于deque的容器,将数组分解为多页较小的数组。例如,假设我们有一个n个元素的数组,我们选择一个页面大小p,并创建1+n/p个p元素的数组(页面)。当我们想要重新分配和增长时,我们只需将现有页面留在原地,然后分配新页面。当我们想要缩小时,我们会释放完全空的页面。

缺点是数组访问稍微慢一点,在给定和索引i的情况下,您需要page=i/p和到页面的偏移量i%p来获取元素。然而,我发现这仍然很快,并且提供了一个很好的解决方案。从理论上讲,std::deque应该做一些非常类似的事情,但对于我尝试使用大数组的情况来说,速度非常慢。有关更多详细信息,请参阅有关链接问题的评论和注释。

在给定n个元素的情况下,我们总是保留p-n%p个元素,这也是内存效率低下的原因。即我们只分配或取消分配完整的页面。对于需要重新调整大小和快速访问的大型阵列,这是我能想到的最好的解决方案,但我毫不怀疑还有更好的解决方案。

如果CCD_ 9中的CCD_。

不,不是。你只是swap

没有任何函数可以就地调整大小或在失败时返回0(调整大小)。除了告诉你一个特定的分配实际有多大之外,我不知道有什么操作系统支持这种功能

然而,所有操作系统都支持实现realloc,但是,如果无法就地调整大小,则会进行复制。

因此,你不能拥有它,因为如果你必须添加一个标准函数,C++语言将无法在大多数当前操作系统上实现

有C++11右值引用和move构造函数。

有一个很棒的视频谈话。

即使存在重新分配,实际上,您也只能在复制构造函数中避免问题中提到的#2。但是,在内部缓冲区增长的情况下,重新分配可以保存这四个操作。

  1. 数组的内部缓冲区是连续的吗?如果是,请查看链接的答案
  2. 如果没有,可以选择哈希数组树或数组列表来避免重新分配

有趣的是,g++的默认分配器足够聪明,只要在最初分配的缓冲区结束后有足够的未使用空间,就可以使用相同的地址进行连续的释放和较大大小的分配。虽然我还没有测试我将要声明的内容,但我怀疑malloc/realloc和allocate/deallocate/allocate之间是否存在很大的时间差。

这会导致一个潜在的非常危险的、非标准的快捷方式,如果您知道当前缓冲区后面有足够的空间,那么重新分配不会产生新的地址,则该快捷方式可能会起作用。(1) 在不调用alloc.destroy()的情况下取消分配当前缓冲区(2)分配一个新的、更大的缓冲区并检查返回的地址(3)如果新地址等于旧地址,则愉快地继续;否则,您将丢失数据(4)为新分配的空间中的元素调用allocater.construct()。

除了满足你自己的好奇心之外,我不主张使用它,但它确实适用于g++4.6。

最新更新