std :: vector *在增长容量时有移动对象吗? 或者,分配器可以“重新分配”吗?
另外一个问题启发了以下想法:
std::vector<T>
在增加容量时必须移动所有元素吗?
据我所知,标准的行为是为底层的分配器请求新的大小的整个块,然后移动所有旧的元素,然后销毁旧的元素,然后释放旧的内存。
这种行为似乎是给定标准分配器接口的唯一可能的正确解决scheme。 但是我想知道,修改allocator来提供一个reallocate(std::size_t)
函数会返回一个pair<pointer, bool>
并且可以映射到底层的realloc()
吗? 这样做的好处是,如果操作系统实际上只能扩展分配的内存,那么根本不会有任何移动。 布尔值将指示内存是否已移动。
( std::realloc()
可能不是最好的select,因为如果我们不能扩展,我们不需要复制数据,所以实际上我们想要的东西就像extend_or_malloc_new()
。 编辑:也许是一个is_pod
-trait-基于规则的专业化将允许我们使用实际的realloc
,包括它的按位副本,只是不一般。)
这似乎是一个错过的机会。 最糟糕的情况是,你总是可以实现reallocate(size_t n)
作为return make_pair(allocate(n), true);
,所以不会有任何处罚。
是否有任何问题,使这个function不适合或不适合的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 */ }
当std::vector<T>
耗尽容量时,它必须分配一个新块。 你已经正确的覆盖了原因。
国际海事组织,这将有助于扩大分配器接口。 我们两个人都试图用C ++ 11,但是我们无法获得支持: [1] [2]
我深信,为了做到这一点,需要一个额外的C级API。 我也没能获得支持: [3]
在大多数情况下, realloc
不会扩展内存,而是分配一个单独的块并移动内容。 在首先定义C ++的时候就考虑了这个问题,并且认为当前的界面在一般情况下更简单并且效率不低。
在现实生活中, realloc
能够增长的情况实际上很less。 在malloc
具有不同池大小的任何实现中,很可能新的大小(记住vector
大小必须以几何级数增长)将落入不同的池中。 即使在没有从任何内存池分配的大块的情况下,如果较大的虚拟地址是空闲的,它也只能增长。
请注意,尽piperealloc
有时可以在不移动的情况下增长内存,但是在realloc
完成时它可能已经移动 (按位移动)了内存,而二进制移动将导致所有非PODtypes的未定义行为。 我不知道任何分配器的实现(POSIX,* NIX,Windows),你可以询问系统是否能够增长 ,但是如果需要移动的话会失败。
是的,你是对的,标准的分配器接口不提供memcpy'abletypes的优化。
已经有可能通过boosttypes特征库来确定types是否可以memcpy(不知道它们是否提供开箱即用,或者必须build立一个基于boosttypes的复合types鉴别器)。
无论如何,利用realloc()
可能会创build一个新的容器types,可以明确地利用这个优化。 目前的标准分配器接口似乎不可能。