次の非常に短いコードスニペットについて考えてみましょう。
_#include <stdlib.h>
int main()
{
char* a = malloc(20000);
char* b = realloc(a, 5);
free(b);
return 0;
}
_
Reallocのマニュアルページを読んだ後、2行目で19995余分なバイトが解放されるかどうかは完全にはわかりませんでした。マニュアルページを引用するには:The realloc() function changes the size of the memory block pointed to by ptr to size bytes.
ですが、その定義から、残りが解放されることを確信できますか?
つまり、b
が指すブロックには確かに5つの空きバイトが含まれているので、遅延準拠のアロケータがrealloc行に対して何もしないだけで十分でしょうか?
注:free(b)
行をコメントアウトすると、valgrindが示すように、私が使用するアロケータは19 995余分なバイトを解放するようです:
_==4457== HEAP SUMMARY:
==4457== in use at exit: 5 bytes in 1 blocks
==4457== total heap usage: 2 allocs, 1 frees, 20,005 bytes allocated
_
はい、新しいオブジェクトを割り当てることができるかどうかはC標準によって保証されています。
(C99、7.20.3.4p2)「realloc関数は、ptrが指す古いオブジェクトの割り当てを解除し、sizeで指定されたサイズの新しいオブジェクトへのポインターを返します。」
はい。成功した場合。
コードスニペットは、よく知られた悪質なバグを示しています。
_char* b = (char*) realloc(a, 5);
_
これが成功すると、以前にa
に割り当てられていたメモリが解放され、b
は、元のブロックと重複する場合と重複しない場合がある5バイトのメモリを指します。
ただし、呼び出しが失敗した場合、b
はnull
になりますが、a
はまだ元のメモリを指しているため、引き続き有効です。その場合、メモリを解放するためにfree(a)
を実行する必要があります。
一般的な(危険な)イディオムを使用すると、さらに悪いことになります。
_a = realloc(a, NEW_SIZE); // Don't do this!
_
realloc
の呼び出しが失敗すると、aはnull
になり、元のメモリは孤立し、プログラムが終了するまで元に戻せなくなります。
これは、libcの実装によって異なります。以下のすべてが適合動作です。
それも可能です
この場合、古いデータもそのまま残ります。たとえば、realloc()
の戻り値がそのブロックへのポインターの唯一のコピーを上書きした場合、メモリリークが発生する可能性があります。
賢明なlibc実装は、ヒューリスティックを使用して、どのソリューションが最も効率的かを判断します。
また、この説明は実装レベルであることに注意してください。意味的に、realloc()
は、割り当てが失敗しない限り、常にオブジェクトを解放します。
Realloc関数には次の規約があります。
void * result = realloc(ptr、new_size)
内部で行われていることの正確な詳細は実装固有です。たとえば、結果はptrに等しくなる可能性があります(ただし、new_sizeを超える追加のスペースは変更しないでください)。reallocはfreeを呼び出すか、独自の内部free表現を行う場合があります。重要なことは、reallocがnull以外の値を返した場合、開発者はptrの責任を負う必要がなくなり、reallocがNULLを返した場合も引き続き責任を持つことです。
19995バイトが解放された可能性は低いようです。より可能性が高いのは、reallocが20000バイトブロックを別の5バイトブロックに置き換えたことです。つまり、20000バイトブロックが解放され、新しい5バイトブロックが割り当てられました。