C および C++ では、NULL ポインターを解放しても何も起こりません。
それでも、「メモリを 2 回解放する」とメモリ破損が発生する可能性があると言う人を見かけます。
これは本当ですか?メモリを 2 回解放すると、内部で何が起こっているのでしょうか?
C および C++ では、NULL ポインターを解放しても何も起こりません。
それでも、「メモリを 2 回解放する」とメモリ破損が発生する可能性があると言う人を見かけます。
これは本当ですか?メモリを 2 回解放すると、内部で何が起こっているのでしょうか?
int *p = malloc(sizeof(int));
//value of p is now lets say 0x12345678
*p = 2;
free(p); //memory pointer is freed, but still value of p is 0x12345678
//now, if you free again, you get a crash or undefined behavior.
したがって、free
最初に ing を実行した後は、 を実行する必要がp = NULL
あるため、(万が一)free(p)
が再度呼び出されても、何も起こりません。
メモリを 2 回解放することが定義されていない理由は次のとおりです。
メモリを解放しても、ポインターは null に設定されません。ポインターは、所有していたメモリを指し続けますが、現在は所有権がヒープ マネージャーに戻されています。
ヒープ マネージャーは、古いポインターが指しているメモリを再割り当てした可能性があります。
再度解放することは、 と言うのと同じではなく、free(NULL)
未定義の動作が発生します。
これは未定義の動作であり、ヒープの破損やその他の重大な結果を招く可能性があります。
free()
null ポインターの場合は、単に内部のポインター値をチェックして戻ります。このチェックは、ブロックを 2 回解放することに対しては役に立ちません。
ここでは、通常何が起こるかを示します。ヒープ実装はアドレスを取得し、独自のサービス データを変更して、そのアドレスにあるブロックの「所有権を取得」しようとします。ヒープの実装に応じて、何かが起こる可能性があります。機能しても何も起こらないかもしれません。サービス データが破損していて、ヒープが破損している可能性があります。
だからやらないでください。未定義の動作です。どんな悪いことでも起きます。
はい、ほとんどの場合クラッシュにつながる「未定義の動作」です。(定義上、「未定義の動作」は「何でも」を意味しますが、さまざまな種類のエラーはしばしば非常に予測可能な方法で動作します。free() の場合、動作は常に segfault または OS に特有のそれぞれの「メモリ保護エラー」です。)
NULL または malloc したもの以外へのポインターを free() する場合も同様です。
char x; char* p=&x; free(p);
// クラッシュ。
フリー 2 回を回避するために、私は常にフリー メモリに MACRO を使用しています。
#ifdef FREEIF
# undef FREEIF
#endif
#define FREEIF( _p ) \
if( _p ) \
{ \
free( _p ); \
_p = NULL; \
}
このマクロは、ポインターのダングリングを避けるために p = NULL を設定します。
ポインタでfreeを呼び出すと、ポインタはNULLに設定されません。空き領域はプールに戻されるだけで、再度割り当てに使用できます。テストする例を次に示します。
#include <stdio.h>
#include <stdlib.h>
int main(){
int* ptr = (int*)malloc(sizeof(int));
printf("Address before free: %p\n", ptr);
free(ptr);
printf("Address after free: %p\n", ptr);
return 0;
}
このプログラムは私のために出力します:
Address before free: 0x950a008
Address after free: 0x950a008
ご覧のとおり、freeはポインタに対して何もしませんでしたが、メモリが再利用可能であることをシステムに通知しただけです。
free() は、ptr が指すメモリー空間を解放します。これは、以前の malloc()、calloc()、または realloc() への呼び出しによって返されたものでなければなりません。それ以外の場合、または free(ptr) が以前に呼び出された場合、未定義の動作が発生します。ptr が NULL の場合、何も実行されません。
したがって、未定義の動作が発生し、何かが起こる可能性があります。
1) 動的メモリの処理はコンパイラによって行われません。これを処理するランタイム ライブラリがあります。たとえば。: glibc は、malloc や free などの API を提供します。これらは、ヒープ領域を処理するためのシステム コール (sys_brk) を内部的に作成します。
2) 同じメモリを 2 回解放するとは、次のような状態を指します。char *cptr; があるとします。
以下を使用してメモリを割り当てます: cptr = (char *) malloc (SIZE);
このメモリが不要になったら、次を使用して解放できます: free(cptr);
ここで、cptr が指すメモリが自由に使用できるようになります。
プログラムの後で free(cptr) を再度呼び出したとします。これは有効な条件ではありません。同じメモリを 2 回解放するこのシナリオは、「メモリを 2 回解放する」問題として知られています。
メモリを複数回解放すると、悪い結果が生じる可能性があります。このコードを実行して、コンピューターで何が起こるかを確認できます。
#include <stdio.h> /* printf, scanf, NULL */
#include <stdlib.h> /* malloc, free, rand */
int main ()
{
int i,n;
char * buffer;
printf ("How long do you want the string? ");
scanf ("%d", &i);
buffer = (char*) malloc (i+1);
if (buffer==NULL) exit (1);
for (n=0; n<i; n++)
buffer[n]=rand()%26+'a';
buffer[i]='\0';
printf ("Random string: %s\n",buffer);
free (buffer);
free (buffer);
return 0;
}
CSparse などの多くの標準ライブラリは、メモリの問題を処理するラッパー関数を使用します。ここに関数をコピーしました:
/* wrapper for free */
void *cs_free (void *p)
{
if (p) free (p) ; /* free p if it is not already NULL */
return (NULL) ; /* return NULL to simplify the use of
}
この関数は、メモリの問題を処理できます。場合によっては malloc が NULL を返す条件に注意する必要があることに注意してください。