8

データへのvoid*を含むノード構造体とheadへの参照を保持するリスト構造体を使用したジェネリックリンクリストの実装があります。これが私の問題です。リンクリスト内のノードが、そのvoid*を介して別のリンクリストへの参照を保持している可能性があります。これにより、小さいリストを含む大きいリストを解放すると、メモリリークが発生します。したがって、void *が別のリストを指しているかどうかを確認する方法があるので、それをフォローして解放するか、データだけを解放する方法があるのでしょうか。

構造体の先頭にキーを追加すると、void *を逆参照して、それがリストであることがわかるマジックナンバーを確認できますか?

編集:呼び出し元は、私の関数によって挿入された小さなリストを挿入しません。呼び出し元が、ポインターを保持しているリストだけを複数のリストに再配置することを処理したくありません。

4

4 に答える 4

6

この質問は、リスト内のエントリをクリーンアップする責任が誰にあるかによって異なります。構造体がフィールドによって参照されるメモリのクリーンアップを担当している場合、void *ここではるかに大きな問題が発生します。つまり、void *任意のメモリブロックを参照している場合、それを割り当て解除する正しい方法がわからないということです。たとえば、C ++の行に沿って動的配列を実装している場合、std::vectorそれvoid *自体にポインタが含まれている構造体を指す可能性があります。リストは、再帰的に解放するためにその構造体に降りる必要があることを知る必要があります。その動的に割り当てられたブロック。ネストされたリストをリークしている、あなたが説明しているケースは、このより一般的な問題の特殊なケースにすぎません。

一方、リストがvoid *格納するsによって参照されるメモリをクリーンアップする責任がリストにない場合は、この問題についてまったく心配する必要はありません。

リストに所有権のセマンティクスがあり、リストに格納されている要素のメモリをクリーンアップする必要がある場合は、ネストされたリストがあるかどうかを判断するためにマジックナンバーを使用しないことを強くお勧めします。むしろ、リストに挿入された要素に対して実行するための割り当て解除ルーチンを含む関数ポインターをクライアントに提供させる必要があります。そうすれば、コードはユーザーが提供したクリーンアップコードを使用して、リストに格納されているすべての要素が確実にクリーンアップされるようにすることができます。

于 2011-02-10T01:19:58.833 に答える
1

void*リストを指すことができるというだけではありません。動的に割り当てられたメモリを指す可能性があります。

GLibがこの問題を処理する方法は、リストのが指しているものがすべてvoid *data解放されるようにするのは呼び出し元の責任であると言うことです。http://library.gnome.org/devel/glib/unstable/glib-Doubly-Linked-Lists.html#g-list-freeを参照してください。

別の方法(GLibも提供)は、関数ポインターを受け取りvoid *data、リストをトラバースするときにそれぞれでそれを呼び出す関数を作成することです。見上げるg_list_free_full

于 2011-02-10T01:19:50.563 に答える
1

私のアドバイスは、可能であれば少し単純化して、1つのリンクリストが1つのタイプのオブジェクトのみを保持するようにすることです。

それができない場合は、リスト内の各ノードに、一部のデータだけでなく、そのタイプのアイテムを適切に解放する方法を知っている関数へのポインターも保持させることができます。必然的に、リンクリスト用の特別なコードを記述してから2週間後に、動的配列などを保持できるようにするために別のマジックナンバーも必要になると判断します。

于 2011-02-10T01:20:02.297 に答える
0

「構造体の先頭にキーを追加すると、void *を逆参照してリストであることがわかるマジックナンバーを追加できますか?」という質問に答えるために。

はい、あなたはこれを行うことができますが、それを推奨する人はほとんどいません。'magic'値が他の方法で発生する可能性がないことを本当に確認してくださいそれはかなり大きな質問です。他に何を指している可能性があり、符号なし整数のようなものとして表されたときにどのような値を取る可能性があるかを検討する必要があります。それがリストであると判断した場合は、それを解放するため、間違っているとクラッシュして燃える可能性があることを忘れないでください。

最も簡単で効果的な解決策は、ノードがリストを指していることを知る必要がある場合、そのことを示すフラグをノードに提供することです。

リストにすべてのコンテンツを解放する責任を本当に持たせたい場合は、フラグ以上のものが必要です。それぞれを解放する方法を知っている必要があります。これは、IDか、その内容を解放する関数へのポインターのようなものである可能性があります。

于 2011-02-10T02:32:07.857 に答える