如果新大小更小,可以重新分配指针吗?

Posted

技术标签:

【中文标题】如果新大小更小,可以重新分配指针吗?【英文标题】:can realloc move pointer if new size smaller? 【发布时间】:2010-12-16 17:23:36 【问题描述】:

我想知道 C 或 C++ 标准是否保证在以较小(非零)大小调用 realloc 时指针不会更改:

size_t n=1000;
T*ptr=(T*)malloc(n*sizeof(T));
//<--do something useful (that won't touch/reallocate ptr of course)
size_t n2=100;//or any value in [1,n-1]
T*ptr2=(T*)realloc(ptr,n2*sizeof(T));
//<-- are we guaranteed that ptr2==ptr ?

基本上,操作系统是否可以自行决定,既然我们释放了一个大内存块,他想利用所有重新分配来对内存进行碎片整理,并以某种方式移动 ptr2?

【问题讨论】:

【参考方案1】:

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

在大小不等于 0 的情况下成功完成后,realloc() 返回一个指向(可能已移动的)分配空间的指针。

不,不保证

【讨论】:

在该页面的前面,它说“realloc() 函数将 ptr 指向的内存对象的大小更改为 size 指定的大小。对象的内容将保持不变,直到新旧大小中的较小者。如果内存对象的新大小需要移动对象,则释放对象先前实例化的空间。不排除运动,但相对不太可能。 是的,您仍然可以保证之前内存中的内容仍然存在,感谢您指出这一点【参考方案2】:

不保证realloc 将返回相同的位置,句号。

【讨论】:

如果在某处明确说明,那就太好了。不说“X 一定会发生”与明确说明“X 不保证会发生”是不一样的。 @RoG 是的,确实如此。不指定保证意味着没有保证。 @klutt 我明白你的意思,但很高兴看到它在某处明确说明,例如在书中,如果不在文档中。从用户的角度来看,找不到保证意味着要么没有保证,要么他们看错了地方。 @RoG 如果标准中没有说明,那么您可以编写一个没有该保证的一致实现。因此,如果标准不要求它,您通常不能期望它从实现中获得。当然,您仍然可以编写具有此保证的实现,因为它不会违反标准。因此,请查看标准或文档中的特定实现。但这真的很简单,因为标准没有要求,所以一般情况下不存在保证。 @RoG 另外,想要这样的证据有点像Russell's teapot。【参考方案3】:

使用realloc,您绝对无法保证后记的记忆位置。我相信 libc 的默认 malloc 只会不情愿地复制内存,所以实际上你可能没问题。但不要指望它。

【讨论】:

【参考方案4】:

realloc 不需要将块留在原处,即使它适合,实际上最简单的存根实现就是一个示例,它可能不适合:

malloc:拨打sbrkrealloc:致电mallocmemcpyfree:无操作。

这听起来可能很荒谬,但有时对于嵌入式系统,我刚才描述的实现实际上是最佳实现。

【讨论】:

另一个例子是所有相邻分配都是相同大小的块以避免碎片的实现。在这种情况下,一个 32 字节的块不再属于与之前的 4096 字节块相同的位置。 是的。另一个更高级的例子是一个实现,它检查要收缩的块的左侧邻居是否空闲,是否会通过收缩在右侧创建一个重要的空闲块,结果大小是否“足够小” " memcpy 不会太贵...如果满足正确的条件,将块移动到新位置以避免碎片。【参考方案5】:

在我看来,所有当前的答案(在这个答案的时候)都没有参考任何标准文档。

对于 C++,我将参考Working Draft, Standard for Programming Language C++, Document Number: N3337, Date: 2012-01-16, Revises: N3291,根据https://isocpp.org/std/the-standard,它是最接近非免费官方 C++11 标准文档的免费文档;在这里我们可以在 20.6.13 C 库找到:

2 内容与标准 C 库头文件相同, 具有以下更改:[在我看来,列出的更改与 问题]。

所以现在我们必须参考 C 标准。

根据https://***.com/a/83763/15485,最接近非免费官方C11标准文档的免费文档是Programming languages — C, N1570 Committee Draft — April 12, 2011 ISO/IEC 9899:201x;在这里我们发现 7.22.3.5 的 realloc 函数

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

我不是以英语为母语的人,所以由你来解释“可能有”的含义。

【讨论】:

我的母语是英语(并且非常熟悉 C 标准)。引用的文本说新指针可能与旧指针具有相同的值,也可能不同,但这并不意味着这取决于大小。一个基本原理(标准中没有说明)是一个实现可以在不同的位置分配一个较小的块,以减少碎片并使未来的分配更有可能成功。为了保证它在某些情况下不会移动,必须在标准中明确说明。不是。【参考方案6】:

在 Windows 上,C-Runtime 抓取一个堆,然后从该堆分配内存。所以操作系统不会知道单个内存分配,因此不会移动。

【讨论】:

这是不正确的。一方面,Visual C 运行时不直接调用 OS 堆实现。另一方面,HeapReAlloc() 调用确实移动了一些东西。 您需要仔细检查您的文档。请参阅:msdn.microsoft.com/en-us/library/csd157zx.aspx CRT 抓取单个 OS 堆以供内部使用。然后它再分配该堆(这意味着它不使用 Win32 堆调用在该堆内进行分配)

以上是关于如果新大小更小,可以重新分配指针吗?的主要内容,如果未能解决你的问题,请参考以下文章

如果我重新分配并且新大小为 0,会发生啥情况。这是不是等同于免费?

我是不是应该强制重新分配检查新块大小是不是小于初始块?

怎样构建更小的容器

Gridster 与 Highcharts,使特定图表更小并重新计算

mxDestroyArray 会正确释放重新分配的矩阵或更改大小的矩阵吗?

当向量需要更多内存并重新分配内存时,指针会发生啥?