36

在 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_nownum_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

无法完全改变内存大小的分配器可以通过 unconditional 实现这样的功能return false;

是否有这么少的能够重新分配的分配器实现不值得打扰?还是我忽略了一些问题?

4

5 回答 5

19

来自: http ://www.sgi.com/tech/stl/alloc.html

这可能是最有问题的设计决定。提供一个重新分配的版本可能会更有用一些,它要么更改现有对象的大小而不复制,要么返回 NULL。这将使它对具有复制构造函数的对象直接有用。在原始对象没有完全填充的情况下,它也可以避免不必要的复制。

不幸的是,这将禁止使用 C 库中的 realloc。这反过来又会增加许多分配器实现的复杂性,并且会使与内存调试工具的交互更加困难。因此,我们决定反对这种选择。

于 2010-06-23T21:41:26.947 回答
15

这实际上是 Alexandrescu 用标准分配器指出的一个设计缺陷(不是 operator new[]/delete[],而是最初用于实现 std::vector 的 stl 分配器,例如)。

realloc 的发生速度明显快于 malloc、memcpy 和 free。但是,虽然可以调整实际内存块的大小,但它也可以将内存移动到新位置。在后一种情况下,如果内存块由非 POD 组成,则所有对象都需要在重新分配之后被销毁和复制构造。

标准库需要适应这种可能性的主要事情是作为标准分配器公共接口的一部分的重新分配函数。即使默认实现是分配新大小的块并释放旧块,像 std::vector 这样的类当然可以使用它。它需要是一个能够销毁和复制构建内存中对象的函数,但如果这样做,它就不能以不透明的方式处理内存。那里涉及一些复杂性,并且需要更多的模板工作,这可能是标准库中省略它的原因。

std::vector<...>::reserve 是不够的:它解决了可以预期容器大小的不同情况。对于真正可变大小的列表,realloc 解决方案可以使像 std::vector 这样的连续容器更快,特别是如果它可以处理内存块成功调整大小而不被移动的 realloc 情况,在这种情况下它可以省略调用 copy内存中对象的构造函数和析构函数。

于 2010-06-24T09:41:42.087 回答
8

你所要求的本质上是什么vector::reserve。如果没有对象的移动语义,就无法在不进行复制和销毁的情况下重新分配内存和移动对象。

于 2010-06-23T20:05:56.300 回答
2

我想这是上帝出错的地方之一,但我懒得写信给标准委员会。

数组分配应该有一个重新分配:

p = renew(p) [128];

或类似的东西。

于 2010-06-23T19:55:04.973 回答
2

由于 C++ 面向对象的特性,以及各种标准容器类型的包含,我认为与 C 相比,方向内存管理的关注更少。我同意在某些情况下 realloc() 会很有用,但是解决这个问题的压力很小,因为几乎所有最终的功能都可以通过使用容器来获得。

于 2010-06-23T20:00:56.457 回答