6

私はオンラインで見つけた次のリンクリストコードを見ています。

void DeleteAfter(Node **head){
      if(*head==NULL){
            return;
      }else{
            Node *temp = NULL;
            temp = (*head)->next;
            (*head)->next = (*head)->next->next;
            delete temp;
            temp=NULL;
      }
}

私はC++にそれほど熟練していないので、これは悪い質問かもしれませんが、削除された後にtempがNULLに設定されるのはなぜですか?これは必要なステップですか?

4

6 に答える 6

8

不要です。結果が出ない場合でも、これを行う習慣をつける人もいます。アグレッシブなコンパイラオプティマイザはこのコードを排除するため、実際には害はありません。しかし、私は書いたでしょう:

void DeleteAfter(Node *head) {
  if (head) {
    Node *next = head->next;
    if (next) {
      head->next = next->next;
      delete next;
    }
  }
}

注:無駄なレベルの間接参照を削除し、削除する「後のノード」があることを確認するためのチェックを追加しました。

習慣の理論的根拠は、ポインターが常に有効なオブジェクトまたはnullのいずれかを参照している場合、有効性チェックと同等のnullチェックに依存できるということです。

このため、セーフティクリティカルシステムでよく使用される言語であるAdaは、ポインタをnullに初期化しdelete、引数を自動的にnullに設定するための同等の演算子を定義します。C++はこの動作をシミュレートしています。

実際には、この分野の価値はあなたが望むものではありません。久しぶりにばかげたエラーを防ぎます。ただし、1つの優れた点は、ポインターコンテンツのデバッガー表示が理にかなっていることです。

于 2013-01-19T17:07:50.750 に答える
2

変数tempがコードの後半で再び使用される可能性がある場合は、変数をNULLに設定することをお勧めします。

通常、ポインタを解放した後にNULLに設定する理由は2つあります。

1.)ポインタを離すと、ポイントされたアドレスのメモリがプログラムで使用できなくなります。理論的には、そのメモリは、オペレーティングシステム自体を含む他のプログラムで使用できるようになりました。すでにリリースされているポインタをリリースしようとしているため、大きな問題を引き起こす可能性のあるものを誰が知っているかを示します。幸いなことに、最新のオペレーティングシステムはこれを防ぎますが、プログラムは不正なアクセスエラーでクラッシュします。ヌルポインタOTOHを解放しても、まったく何も起こりません。

2.)演算子で参照を解除する前に、ポインタがNULLでないことを常に確認する必要があります*。NULLポインターを逆参照すると、実行時エラーが発生します。任意のメモリを指す解放されたポインタの参照を解除すると、さらに悪化します。解放されたポインタは常にに設定する必要がありますNULL。これにより、後のコードでnull以外のポインタが有効なデータを指していると見なすことができます。そうしないと、ポインタがまだ有効かどうかを知る方法がありません。

元の質問に関しては、ポインター変数tempは、二度と使用されない短い関数でローカル変数として宣言されています。この場合、関数が戻るとすぐにスコープから外れるため、NULLに設定する必要はありません。

しかし、ライン...

(*head)->next = (*head)->next->next;

(*head)->next参照解除を試みる前に、nullでないことを確認できません。

より良いバージョンは...

int DeleteAfter(Node **head){
  Node *node_after = NULL;

  if(*head==NULL)
    return -1;

  node_after = (*head)->next;

  if(node_after == NULL)
    return -1;

  (*head)->next = node_after->next;
  delete node_after;

  return 0;
  }

これで、関数を使用する人は、戻り値によってノードの削除が成功したかどうかを確認でき、存在しないノードを削除しようとするリスクはありません。

于 2013-01-19T22:21:25.973 に答える
1

ローカルポインタ変数を削除した後、NULLに設定する必要はありません。ポインタを再利用する場合は、ポインタをNULLに設定する必要があります。NULLチェック後、uは新しいアドレスを安全に割り当てることができます。通常、ポインタメンバーに対して行います。変数とグローバルポインタ変数。

于 2013-01-19T17:14:05.583 に答える
1

tempがグローバル変数またはメンバー変数である場合、NULLに設定することは悪い考えではありません。

Cコードで保守的なガベージコレクターを使用した後、ポインターをNULLに設定する習慣がありました。未使用のメモリへのポインタがないことが、収集するガベージを見つける方法です。しかし、この場合、あなたもする必要があります

temp->next = NULL;
于 2013-01-19T17:48:45.493 に答える
0

コード例では、明らかな即時のメリットはありませんが、間違いなく、長期的なメンテナンスコストのメリットがあります。tempの逆参照を試みるtempを削除した後、誰かが最終的にコードを追加する可能性があるという考えです。これは、削除に気付かないか、削除後にtempにアクセスする以前の行を移動することによって簡単に発生する可能性があります。

次に例を示します。

int * i = new int(12);
std::cout << *i << std::endl; // output is 12.
delete i;
// i = 0; // This would cause the program to fail on the next line.
std::cout << *i << std::endl; // output is random for me.

これは欠陥を隠さないことに注意してください。実際、ポインタをnullに設定しないと、この場合、* iがランダムな値を返すため、欠陥が隠されます。

ほとんどの場合、i = 0はコンパイラによって最適化される可能性が高く、どちらの方法でも、ポインタへの割り当てはほとんど無害です。私にとって、プロとして開発するときは常に注意を怠ります。

于 2015-08-13T16:39:05.483 に答える
-1

それは必要ではなく、一部の人(私を含む)はそれを悪い習慣だと考えています。

に設定する動機NULLは、後で削除されたかどうかを確認し、削除されていない場合はアクセスできるようにすることです。また、これにより、二重削除が防止されます。これdeleteは、NULLポインターでは何も実行されないためです。

一方、それはバグを隠すことができます。オブジェクトが削除された場合、それを使用しても意味がありませんよね?チェックに頼るのではなく、オブジェクトが削除されたことを知っておく必要があります。

例えば

if (p != NULL) //or just if (p)
   p->doStuff()

なんで?削除されたかどうかはもうわかりませんか?クリーンアップはロジックの一部ではありませんか?

于 2013-01-19T17:07:25.680 に答える