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 */ }
答案 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()
,可能会创建一个可以明确利用此优化的新容器类型。使用当前的标准分配器接口似乎不可能。