【问题标题】:Is realloc guaranteed to be in-place when the buffer is shrinking?当缓冲区缩小时,realloc 是否保证就位?
【发布时间】:2010-07-02 00:06:35
【问题描述】:

是否有任何保证 realloc() 将始终就地缩小缓冲区?如下:

new_ptr = (data_type *) realloc(old_ptr, new_size * sizeof(data_type));

如果 new_size

我正在研究非 POD 数据类型数组的重新分配,如果上述行为得到保证,我认为以下策略至少可以实现有效的“收缩”:

if (new_size > old_size)
{
    // malloc() a new buffer
    // use placement copy constructor to copy old objects over
    // free() old buffer
}
else
if (new_size < old_size)
{
    // explicit destruction of unneeded objects
    // realloc() buffer
}

我希望即使数据类型具有自引用/指针或其他任何内容,就地“收缩”也会很健壮......

【问题讨论】:

  • 感谢大家的cmets。我想我只是觉得必须分配一个新缓冲区并进行完整复制以实现“缩小”是非常浪费和低效的......
  • 这里不打算加入“不”的合唱,你现在应该明白了。但是,保证重新分配的块在收缩时重用相同内存的一个意外副作用是,您不能在 malloc/realloc 中使用 small object allocator,因为这些分配器将大小相等的对象组合在一起。
  • 另一个你不能期望 realloc 总是重用相同内存的原因是大多数通用堆将管理信息(块大小,指向堆中下一个块的指针)放在“前面”的标题中分配的内存。因此,如果您有一个位于两个已分配块之间的块,并重新分配给一个较小的字,则没有空间为已释放的内存字放置标头,从而有效地丢失它并永久分割您的堆。
  • 如果您尝试使用 malloc 和朋友管理非 POD 数据数组,那么您将导致未定义的行为。无论这个特定问题的答案如何,您所做的都是错误的。使用new[]delete[],或诸如std::vector 之类的容器(顺便说一句,它们会原地收缩)。
  • @Mike:对不起,我不同意。使用 malloc()/free() 等结合通过放置 new() 等对 ctor/dtor 的显式调用应该得到很好的定义。大多数 std::vector 实现分别管理底层缓冲区和对象构造,而不是通过 new[]/delete[]...

标签: c++


【解决方案1】:

没有。

就是这样。这些都不是“它可能在某些架构中工作”或“它应该,基于经验”。标准明确规定地址可能会改变,因此仅依靠 that 仅此而已。在任何情况下,您都询问是否保证 - 答案是肯定的否(a)

在编码到标准方面:做或不做。没有“尝试”:-)


来自 c99:

realloc 函数释放ptr 指向的旧对象,并返回一个指向具有size 指定大小的新对象的指针。新对象的内容应与释放前旧对象的内容相同,直至新旧大小中的较小者。新对象中超出旧对象大小的任何字节都具有不确定的值。

如果ptr 是空指针,则realloc 函数的行为类似于指定大小的malloc 函数。否则,如果ptr 不匹配之前由callocmallocrealloc 函数返回的指针,或者如果空间已通过调用freerealloc 函数被释放,行为未定义。如果无法为新对象分配内存,则不会释放旧对象并且其值不变。

realloc 函数返回一个指向新对象的指针(可能与一个指向旧对象的指针具有相同的值),或者一个空指针,如果无法分配新对象。


(a) 如果您想知道为什么,您不会只是将一个缓冲区分成两个较小的缓冲区(保留一个并将另一个返回到空闲列表) 为了提高效率,至少有一种可能性浮现在脑海中。

如果您有不同的池用于不同大小的分配(例如,可能使用不同的分配策略),则将数据移到池中以进行较小的分配可能是有意义的。您从单独的池中获得的效率提升可能超过保留内存的收益。

但这只是一个例子,我不知道是否有任何实现这样做。如前所述,您应该依赖标准的要求,即即使缩小内存也可能移动。

【讨论】:

    【解决方案2】:

    没有。你不能依赖这个。

    根据规范 7.20.3.4/4:

    realloc 函数返回一个指针 到新对象(可能具有 与指向的指针相同的值 旧对象),或空指针 如果新对象不能 已分配。

    【讨论】:

      【解决方案3】:

      通常会,但不是保证(这完全取决于您的架构)。所以你不应该依赖这种行为

      编辑:

      参考:http://opengroup.org/onlinepubs/007908775/xsh/realloc.html

      成功完成后的尺寸 不等于 0,realloc() 返回一个 指向(可能已移动)的指针 分配空间。

      【讨论】:

        【解决方案4】:

        一些分配器使用“分桶”策略,其中大小从 2^3 到 2^4 的分配进入同一个分配桶。这往往可以防止内存碎片的极端情况,其中许多小分配分布在堆中会阻止大分配成功。显然,在这样的堆管理器中,减小分配的大小可能会强制分配到不同的存储桶。

        【讨论】:

          【解决方案5】:

          不,没有这样的保证。 realloc 的实现可能只是将缓冲区缩小到适当的位置,但它们不受限制这样做。

          【讨论】:

            猜你喜欢
            • 2010-10-21
            • 2010-12-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多