6

割り当てたメモリへのポインタのみを含む構造体があります。各要素でfreeを呼び出すのではなく、ポインターである各要素を再帰的に解放する方法はありますか?

たとえば、次のレイアウトがあるとします。

typedef struct { ... } vertex;
typedef struct { ... } normal;
typedef struct { ... } texture_coord;

typedef struct
{
    vertex* vertices;
    normal* normals;
    texture_coord* uv_coords;
    int* quads;
    int* triangles;
} model;

そして私のコードでは、モデルを作成するために各構造体をmallocします。

model* mdl = malloc (...);
mdl->vertices = malloc (...);
mdl->normals = malloc (...);
mdl->uv_coords = malloc (...);
mdl->quads = malloc (...);
mdl->triangles = malloc (...);

次のように各ポインタを解放するのは簡単です。

free (mdl->vertices);
free (mdl->normals);
free (mdl->uv_coords);
free (mdl->quads);
free (mdl->triangles);
free (mdl);

各要素でfreeを呼び出すのではなく、mdlのポインターを再帰的に繰り返す方法はありますか?

実際には、それぞれにfree()を記述するだけの作業はほとんどありませんが、コードの重複を減らし、そこから学ぶのに役立ちます

4

8 に答える 8

20

実際にはそうではありませんが、6つすべての解放を実行するメソッドを記述して、1つを見逃さないようにすることはできます。

void freeModel( model* md1 ) {
    free (mdl->vertices);
    free (mdl->normals);
    free (mdl->uv_coords);
    free (mdl->quads);
    free (mdl->triangles);
    free (mdl);
}
于 2009-06-03T01:17:54.247 に答える
8

このような機能は C に組み込まれていませんが、マクロ プリプロセッサを悪用して少しごまかすことができます。

#define XX_MODEL_POINTERS do { \
  xx(vertices); xx(normals); xx(uv_coords); xx(quads); xx(triangles); \
} while(0)

割り当てるには:

model *mdl = malloc(sizeof(*mdl));
assert(mdl);
#define xx(N) mdl->N = malloc(sizeof(*mdl->N)); assert(mdl->N)
XX_MODEL_POINTERS;
#undef xx

無料に:

assert(mdl);
#define xx(N) free(mdl->N); mdl->NULL
XX_MODEL_POINTERS;
#undef xx
free(mdl);
mdl = NULL;

厄介なのは、 の定義struct modelと の定義がXX_MODEL_POINTERS相互に矛盾する可能性があり、それを把握する方法がないことです。このため、XX_MODEL_POINTERSどこかで .h ファイルを解析して の定義を生成する方がよい場合がよくあります。

C でのメタプログラミングは決して簡単ではありません。

于 2009-06-03T01:52:55.240 に答える
7

これを行う方法はC言語にはありません。また、望ましいことでもありません。Cは、各メンバーがmallocを介して割り当てられた個別のポインターであることを認識しておらず、実行時にこれを行うためのランタイム型情報サポートが含まれていません。構造体にアクセスするためにコンパイルされたコードは、各メンバーアクセスのベースポインターからのオフセットを使用しているだけです。

最も簡単なアプローチは、「FreeModel」関数を作成することです。

void FreeModel(model* mdl)
{
   free(mdl->vertices);
   ... // Other frees
   free(mdl);
}
于 2009-06-03T01:20:48.783 に答える
4

以下の場合は、talloc http://talloc.samba.org/を参照してください。

model* mdl = talloc (NULL, ...);
mdl->vertices = talloc (mdl, ...);
mdl->normals = talloc (mdl, ...);
mdl->uv_coords = talloc (mdl, ...);
mdl->quads = talloc (mdl, ...);
mdl->triangles = talloc (mdl, ...);

その後、次のことができます。

talloc_free(mdl);

そして、割り当て時に最初の引数として呼び出した他のすべてのブロックを処理します(これは再帰的に実行されtalloc、それも取得されます)freetallocmdltalloc(mdl->vertices, ...)talloc_free(mdl);

余談ですが、talloc を使用すると、再帰の対象を追跡する必要があるため、わずかなオーバーヘッドが発生しますが、それほど多くはありません。

于 2010-06-17T20:26:49.003 に答える
3

それらすべてに必要なサイズを一緒に計算して、1つの大きなmallocを実行できます

sizeof(model)+ sizeof(vertex)*nVertices...など。

結果をmdlに割り当て、result + sizeof(model)をmodel->verticesに割り当てます。

次に、解放するのは1つだけです。

(プラットフォームによっては)配置の問題について心配する必要があるかもしれませんが、それを理解するのはそれほど難しいことではありません。もう1つの問題は、それがはるかに大きなチャンクであり、メモリに制約のある環境にある場合に問題が発生する可能性があることです。

于 2009-06-03T01:21:45.783 に答える
2

関数内のすべての無料を投げますか?

于 2009-06-03T01:18:27.523 に答える
0

私はそれがどんな形のCでも可能であるとは思わない。

その特定の構造に対して別の関数をコーディングして、ポインターを渡し、そこで解放することができます。

編集:アップ、遅すぎる、それらの答えを見たことがない...

于 2009-06-03T01:18:34.123 に答える
0

それらの構造ではありません。解放するポインタのリストを含む別のエントリをトップレベルの「model」構造体に追加し、そのリストを繰り返すことができます。しかし、そのソリューションの複雑さが増し、理解しやすさが低下する価値があるかどうかは疑問です。(ここに示しているよりも、トップレベルの「モデル」構造体で解放するエントリのセットがはるかに大きく、より深くネストされている場合を除きます。)

于 2009-06-03T01:18:48.117 に答える