在C中,标准内存处理函数是malloc()
,realloc()
和free()
。但是,C ++ stdlib分配器只兼容其中两个:没有重新分配功能。当然,不可能与realloc()
完全相同,因为简单地复制内存不适合非聚合类型。但是,这个功能会出现问题:
bool reallocate (pointer ptr, size_type num_now, size_type num_requested);
,其中
ptr
以前为num_now
个对象分配了相同的分配器; num_requested
> = num_now
; 和语义如下:
ptr
的给定内存块从num_now
个对象的大小扩展到num_requested
个对象,它会这样做(留下额外的内存未初始化)并返回true
; false
。当然,这不是很简单,但据我所知,分配器主要用于容器和容器的代码通常很复杂。
鉴于这样的功能,std::vector
,比如说,可以增长如下(伪代码):
if (allocator.reallocate (buffer, capacity, new_capacity))
capacity = new_capacity; // That's all we need to do
else
... // Do the standard reallocation by using a different buffer,
// copying data and freeing the current one
无法完全改变内存大小的分配器可以通过无条件return false;
实现这样的功能。
是否有这么少的可重新分配的分配器实现,不值得打扰?还是有一些我忽略的问题?
答案 0 :(得分:19)
自: http://www.sgi.com/tech/stl/alloc.html
这可能是最值得怀疑的 设计决定。它会的 对我来说可能更有用了 提供重新分配的版本 要么改变了大小 现有对象无需复制或 返回NULL。这样就可以了 直接用于具有副本的对象 构造函数。它也会 避免不必要的复制 其中原始物体没有 已完全填写。
不幸的是,这会有 禁止使用C中的realloc 图书馆。这反过来会增加 许多分配器的复杂性 实现,并将成为 与内存调试的交互 工具更难。因此我们决定了 反对这种选择。
答案 1 :(得分:13)
这实际上是Alexandrescu用标准分配器指出的设计缺陷(不是operator new [] / delete [],而是最初用于实现std :: vector的stl分配器,例如)。
realloc的发生速度明显快于malloc,memcpy和free。但是,虽然可以调整实际内存块的大小,但它也可以将内存移动到新位置。在后一种情况下,如果内存块由非POD组成,则需要在重新分配后销毁所有对象并进行复制构造。
标准库需要将其作为可能性来满足的主要特点是作为标准分配器公共接口的一部分的重新分配功能。像std :: vector这样的类当然可以使用它,即使默认实现是malloc新大小的块并释放旧块。它需要是一个能够在内存中销毁和复制构造对象的函数,但如果它这样做,它就不能以不透明的方式处理内存。这里有一点复杂性,需要更多的模板工作,这可能是它从标准库中省略的原因。
std :: vector< ...> :: reserve是不够的:它解决了可以预期容器大小的不同情况。对于真正可变大小的列表,realloc解决方案可以使std :: vector等连续容器更快,特别是如果它可以处理内存块成功调整大小而不被移动的realloc情况,在这种情况下它可以省略调用副本内存中对象的构造函数和析构函数。
答案 2 :(得分:8)
你所要求的基本上是vector::reserve
所做的。没有对象的移动语义,就没有办法重新分配内存并移动对象而不进行复制和销毁。
答案 3 :(得分:3)
由于C ++的面向对象特性以及各种标准容器类型的包含,我认为简单地说,方向内存管理比C更少关注。我同意有些情况下realloc()这将是有用的,但解决这个问题的压力是微乎其微的,因为几乎所有产生的功能都可以通过使用容器来获得。
答案 4 :(得分:2)
我想这是上帝出错的事情之一,但我只是懒得写标准委员会。
应该有一个数组分配的重新分配:
p = renew(p) [128];
或类似的东西。