std :: vector *在增加容量时是否有*移动对象?或者,分配器可以“重新分配”吗?

时间:2011-11-03 23:30:37

标签: c++ vector realloc allocator

different question启发了以下想法:

std::vector<T> 是否在增加容量时移动所有元素?

据我了解,标准行为是底层分配器请求新大小的整个块,然后移动所有旧元素,然后销毁旧元素,然后释放旧内存。

在给定标准分配器接口的情况下,此行为似乎是唯一可行的正确解决方案。但我想知道,修改分配器以提供reallocate(std::size_t)函数是否有意义,该函数将返回pair<pointer, bool>并可映射到基础realloc()?这样做的好处是,如果操作系统实际上只能扩展分配的内存,那么根本不需要移动。布尔值表示内存是否已移动。

std::realloc()可能不是最好的选择,因为如果我们无法扩展,我们不需要复制数据。所以实际上我们更想要extend_or_malloc_new()之类的东西。编辑:也许is_pod - 基于特质的专业化将允许我们使用实际的realloc,包括其按位副本。只是不一般。)

这似乎错过了机会。最糟糕的情况是,您可以始终将reallocate(size_t n)实施为return make_pair(allocate(n), true);,这样就不会有任何惩罚。

是否有任何问题导致此功能对C ++不合适或不合适?

也许唯一可以利用此功能的容器是std::vector,但这又是一个非常有用的容器。


更新:澄清一个小例子。当前resize()

pointer p = alloc.allocate(new_size);

for (size_t i = 0; i != old_size; ++i)
{
  alloc.construct(p + i, T(std::move(buf[i])))
  alloc.destroy(buf[i]);
}
for (size_t i = old_size; i < new_size; ++i)
{
  alloc.construct(p + i, T());
}

alloc.deallocate(buf);
buf = p;

新实施:

pair<pointer, bool> pp = alloc.reallocate(buf, new_size);

if (pp.second) { /* as before */ }
else           { /* only construct new elements */ }

3 个答案:

答案 0 :(得分:42)

std::vector<T>用完容量时, 分配新块。你已经正确地说明了原因。

IMO 有意义地扩充分配器接口。我们两个人试图使用C ++ 11而我们无法获得对它的支持:[1] [2]

我确信为了使这项工作,需要一个额外的C级API。我也未能获得支持:[3]

答案 1 :(得分:9)

在大多数情况下,realloc不会扩展内存,而是分配一个单独的块并移动内容。在首先定义C ++时考虑了这一点,并且在常见情况下确定当前接口更简单且效率不高。

在现实生活中,实际上realloc能够成长的情况很少。在malloc具有不同池大小的任何实现中,新大小(请记住vector大小必须在几何上增长)可能会落入不同的池中。即使在没有从任何内存池分配的大块的情况下,如果更大的虚拟地址是免费的,它也只能增长。

请注意,虽然realloc有时可以在没有移动的情况下增长内存,但到realloc完成时它可能已经移动(按位移动)内存,并且二进制移动将导致所有非POD类型的未定义行为。我不知道任何分配器实现(POSIX,* NIX,Windows),您可以询问系统是否能够增长,但如果它需要移动<那将失败/ em>的

答案 2 :(得分:0)

是的,你是对的,标准的分配器接口不能为memcpy'able类型提供优化。

可以确定是否可以使用boost类型特征库来记忆类型(不确定它们是否开箱即用,或者必须根据增强类型构建复合类型鉴别器)。 / p>

无论如何,要利用realloc(),可能会创建一个可以明确利用此优化的新容器类型。使用当前的标准分配器接口似乎不可能。