7

我想使用 realloc 来增加内存大小,同时保持指针不变(因为调用者使用它)。realloc 并不总是这样做;有时它会返回一个不同的指针并释放旧指针。我想“尝试”重新分配内存,如果不可能,请使用原始指针回退到不同的方法 - 但 realloc 已经破坏了它!

如果不可能,有没有办法尝试增加 malloc 的内存而不破坏(如 realloc 那样)旧指针?

例如

void *pold;
void *pnew = realloc(pold, newsize);
if (pnew != pold)
{
     free(pnew);
     DoDifferently(pold); // but pold is freed already
}

PS我不关心可移植性(仅限linux,因此是标签)。

4

7 回答 7

3

您应该查看您正在使用的 libc 中的 realloc() 的源代码。从那里,应该很容易看到当它可以增加大小时所遵循的路径,以及将返回新指针的其他情况。然后,使用它来编写您自己的 tryrealloc() 函数。

例如,这是来自 uclibc 的 realloc() 源代码:http: //cristi.indefero.net/p/uClibc-cristi/source/tree/nptl/libc/stdlib/malloc/realloc.c

24  void *
25  realloc (void *mem, size_t new_size)
26  {
...
57    if (new_size > size)
58    /* Grow the block.  */
59    {
60        size_t extra = new_size - size;
61  
62        __heap_lock (&__malloc_heap_lock);
63        extra = __heap_alloc_at (&__malloc_heap, base_mem + size, extra);
64        __heap_unlock (&__malloc_heap_lock);
65  
66        if (extra)
67          /* Record the changed size.  */
68          MALLOC_SET_SIZE (base_mem, size + extra);
69        else
70          /* Our attempts to extend MEM in place failed, just
71             allocate-and-copy.  */
72        {
73          void *new_mem = malloc (new_size - MALLOC_HEADER_SIZE);
74          if (new_mem)
75            {
76              memcpy (new_mem, mem, size - MALLOC_HEADER_SIZE);
77              free (mem);
78            }
79          mem = new_mem;
80        }
81      }
...

为了清楚起见,我删除了一些部分。但是您可以在第 66 行看到,它检查是否可以简单地为当前指针增加内存。这是您要保留的部分。从第 69 行开始的else情况是处理将释放旧内存并返回新指针的情况。这是您要踢出并以不同方式处理的部分。从你所说的来看,我猜你只想删除第 77 行,它在那里免费。

如果您采用这种方式,请记住您必须手动释放旧指针或新指针,因为两者现在都有效(并且您不希望内存泄漏)。

此外,这是针对 uclibc 的。如果您已经在使用不同的 libc,则应将新tryrealloc()功能基于realloc()该 libc 的功能。

编辑:如果你使用这种方法,你必须小心。您的解决方案将基于内存管理器的内部结构,因此在各种 libc 实现之间以及同一 libc 的不同版本之间,情况可能会发生变化和不同。因此,请牢记适当的注意和警告。

于 2012-12-18T18:48:56.490 回答
1

我不认为有一个可移植的realloc函数可以做到这一点。

一种相对简单的可移植解决方案是预先分配比您最初需要的更大的内存块。这将允许在不更改指针的情况下进行一些增长(实际上,您将在原地进行自己的操作realloc)。

一旦超出原始块,您将不得不分配一个新块来代替。这是您的“失败”场景。

于 2012-12-18T15:58:51.067 回答
1

据我所知,这样的事情是不可能的(使用标准库进行移植)。但是,有一些简单的解决方法。由于您的调用者使用该指针,因此您必须为他们修复它。一种解决方案是:

void *do_something(void *your_pointer)
{
    void *new_pointer;
    new_pointer = realloc(your_pointer, ...);
    /* more logic */
    return new_pointer;
}

并告诉他们这样使用do_something

new_pointer = do_something(my_pointer);
if (new_pointer) /* if returning NULL is at all possible */
    my_pointer = new_pointer;

或者,您可以自己处理:

int do_something(void **pointer_to_your_pointer)
{
    void *new_pointer;
    new_pointer = realloc(*pointer_to_your_pointer, ...);
    /* more logic */
    *pointer_to_your_pointer = new_pointer;
    return error_code;
}

并告诉他们像这样使用它:

do_something(&my_pointer);
于 2012-12-18T16:00:59.243 回答
1

这个问题没有便携的解决方案,非便携的解决方案也不是没有风险的。

与 GNU 一起使用的非便携式解决方案malloc是用来malloc_usable_size找出内存区域的实际大小。但是,即使内存区域足够大,我也不确定是否realloc不能保证使用它。IIRC,曾经有一个选项导致realloc总是分配新内存,但我再也找不到了;不过,我看起来并不难。

于 2012-12-18T16:05:03.370 回答
1

替代的内存管理库jemalloc提供了这样的功能。可以xallocx()这样做:

size_t realsize = xallocx(pold, newsize, 0, 0);
if (realsize < newsize)
{
     DoDifferently(pold);
}
于 2015-10-11T02:55:39.657 回答
0

为什么不只是malloc您可能需要的最大数量?内存通常只会在您使用后才实际分配。要进行微调,您可以使用mmap分配内存区域。

于 2012-12-18T16:00:53.567 回答
0

它不是在程序员手中指向reallocate同一点memory region..你可以增加size使用realloc()..你可能会或可能不会memory location在使用后得到相同的realloc..很可能你可能不会..如果有一个可能没有任何问题内存位置变化..

于 2012-12-24T18:02:12.747 回答