代码之家  ›  专栏  ›  技术社区  ›  doublep

为什么在C++分配器中没有重新分配功能?

  •  34
  • doublep  · 技术社区  · 15 年前

    在C语言中,标准的内存处理功能是 malloc() , realloc() free() . 但是,C++ STDLIB分配器只有两个并行:没有重分配函数。当然,这是不可能做到完全相同的 RealLoad() ,因为简单复制内存不适合非聚合类型。但是,比如说,这个函数是否有问题:

    bool reallocate (pointer ptr, size_type num_now, size_type num_requested);
    

    在哪里?

    • ptr 以前用同一个分配器分配给 num_now 物体;
    • num_requested = 努姆斯诺 ;

    语义如下:

    • 如果分配器可以在 PTR 从尺寸到 努姆斯诺 对象到 请求编号 对象,然后返回 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; .

    是否有如此少的可重新分配的分配器实现,以至于不值得麻烦?还是我忽略了一些问题?

    5 回复  |  直到 15 年前
        1
  •  19
  •   5ound    15 年前

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

    这可能是最值得怀疑的 设计决策。它会有 可能对 提供重新分配版本 或者改变了 不复制或 返回空值。这样就可以了 直接用于具有副本的对象 构造函数。它也会 避免不必要的复制 其中原始对象没有 全部填写完毕。

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

        2
  •  13
  •   stinky472    15 年前

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

    重新分配比malloc、memcpy和free发生得更快。然而,虽然实际内存块可以调整大小,但它也可以将内存移动到新的位置。在后一种情况下,如果内存块由非pods组成,则需要销毁所有对象,并在重新分配后进行复制构造。

    标准库需要将其作为 可能性 是作为标准分配器公共接口的一部分的重新分配函数。像std::vector这样的类当然可以使用它,即使默认实现是malloc新大小的块并释放旧块。它需要一个能够破坏和复制内存中的对象构造的函数,但是如果它这样做了,就不能以不透明的方式处理内存。这里有一点复杂,需要更多的模板工作,这可能就是为什么它被从标准库中省略的原因。

    std::vector<…>::reserve不够:它处理了一个不同的情况,在这种情况下可以预期容器的大小。对于真正可变大小的列表,realloc解决方案可以使std::vector等连续容器更快,特别是当它可以处理内存块成功调整大小而不移动的realloc情况时,在这种情况下,它可以忽略为内存中的对象调用复制构造函数和析构函数。

        3
  •  8
  •   Mark Ransom    15 年前

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

        4
  •  3
  •   tlayton    15 年前

    由于C++的面向对象性质和各种标准容器类型的包含,我认为简单地说,在方向记忆管理上比在C.上放置较少的焦点,我同意RealCuffor()的情况是有用的,但是补救这一点的压力是最小的,因为几乎所有的最终功能都可以。用容器代替。

        5
  •  2
  •   Pavel Radzivilovsky    15 年前

    我想这是上帝出错的原因之一,但我太懒了,没法写信给标准委员会。

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

    p = renew(p) [128];

    或者类似的。