7

realloc を使用して、ポインターを変更せずにメモリサイズを増やしたい (呼び出し元が使用するため)。realloc は常にそうするとは限りません。場合によっては、別のポインターを返し、古いポインターを解放します。メモリの再割り当てを「試み」たいのですが、それが不可能な場合は、元のポインターを使用して別の方法にフォールバックしますが、再割り当てはすでにそれを破壊しています!

不可能な場合、古いポインタを (realloc のように) 破棄せずに malloc されたメモリを増やす方法はありますか?

例えば

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 行目で、現在のポインターのメモリを単純に増やすことができるかどうかを確認していることがわかります。残しておきたい部分です。else69 行目から始まるケースは、古いメモリが解放され、新しいポインタが返されるケースを処理するためのものです。これは、追い出して別の方法で処理したい部分です。あなたが言っていることから、無料を行う77行目だけを削除したいと思うでしょう。

このようにする場合は、古いポインターまたは新しいポインターのいずれかを手動で解放する必要があることに注意してください。これは、両方が有効になるためです (そして、メモリ リークは望ましくありません)。

また、これは uclibc 用です。すでに別の libc を使用している場合は、その libc の関数に基づいて新しいtryrealloc()関数を作成する必要がありますrealloc()

編集:このアプローチを使用する場合は注意が必要です。メモリ マネージャーの内部構造に基づいてソリューションを作成するため、さまざまな libc 実装間だけでなく、同じ libc の異なるバージョン間でも状況が変化し、異なる可能性があります。したがって、適切な注意と警告を念頭に置いてそれを行ってください。

于 2012-12-18T18:48:56.490 に答える
1

私の知る限り、そのようなことは不可能です(移植性のために標準ライブラリを使用しています)。ただし、簡単な回避策があります。発信者はそのポインタを使用するので、それを修正する必要があります。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

reallocこれを行うポータブルタイプの関数はないと思います。

移植可能な比較的簡単な解決策の 1 つは、最初に必要とするよりも大きなメモリ ブロックを事前に割り当てることです。これにより、ポインターを変更せずにある程度の成長が可能になります (実際には、 in situ で独自に行うことになりますrealloc)。

元のブロックを超えると、代わりに新しいブロックを割り当てる必要があります。これがあなたの「失敗」シナリオです。

于 2012-12-18T15:58:51.067 に答える
0

なぜmallocあなたが今までに必要とするかもしれない最大量だけではないのですか?通常、メモリは使用後に実際に割り当てられます。mmap微調整するには、メモリの領域を割り当てるために使用できます。

于 2012-12-18T16:00:53.567 に答える
0

それはプログラマの手にはありませんreallocate..あなたはただ使用をmemory region増やすことができます..あなたは使用後に同じになるかもしれません..ほとんどの場合、あなたはそうではないかもしれません..メモリ位置の変更..sizerealloc()memory locationrealloc

于 2012-12-24T18:02:12.747 に答える