1
int main(){
   //Node is some template class
   Node<int>* head = new Node<int>[5];

   for(int ii = 0; ii < 5; ii++)
   {
      head[ii].set_Data(ii);
      head[ii].set_Link(head + (ii + 1));
      if(ii == 4)
      {
        head[ii].set_Link(NULL);
      }
   }
   delete [] head;
 }


template<typename T>
void Node<T>::set_Link(Node* Node_Address)
{
    Link = Node_Address;
}


template<typename T>
Node<T>::~Node()
{
    delete Link;
    cout << "Destructor" << endl;
}

私は今、リンクリストを学んでいます。デストラクタが15回呼び出され、coutステートメントが15回出力される理由がわかりません。私がステートメントを取り除く場合

head[ii].set_Link(head + (ii + 1));

デストラクタは5回しか呼び出されません。これは、5つのクラスが作成されるため意味があります。クラスではなくポインタのみを渡すときに、メンバー関数set_Link()を使用すると、デストラクタが呼び出されるのはなぜですか。コピーコンストラクターは呼び出されません。助けてくれてありがとう!

4

3 に答える 3

8

ここにUBがあります。デストラクタは複数回呼び出されます。delete [] head;配列内の各オブジェクトのデストラクタを呼び出します。デストラクタは、 を介して、リンクされたオブジェクトのデストラクタを呼び出しますdelete Link;

合計で、デストラクタは 5 + 4 + 3 + 2 + 1 = 15 回呼び出されます。主にすでに破壊されたオブジェクトに。

通常、連結リストの要素に対して配列を作成することはありません。代わりに、次のようにリストを作成します。

Node<int>* head = new Node<int>(); 
Node<int>* node = head;
for(int ii = 0; ii < 5; ii++) 
{ 
  node->set_Data(ii); 
  if(ii == 4) 
  { 
    node.set_Link(NULL); 
  }
  else
  {
    Node<int>* next = new Node<int>();
    node->set_Link(next);
    node = next;
  }
} 
delete head; 
于 2012-07-24T06:32:35.110 に答える
1

リンク リスト ノード デストラクタでは、指定された次のノードを削除したくありません。これにより、すべてのテール ノードがカスケード削除されます。最初にポインターを NULL に設定することでこれを防ぐことができますが、それは単なる保守性の悪夢であり、このような多くの微妙なバグを作成します。

注: 「メンバー関数 set_Link() を使用するとデストラクタが呼び出されるのはなぜですか」 - 呼び出されないため、トレース メッセージをいくつか追加することで、これを簡単に確認できます。すべてのデストラクタ呼び出しは、その 1 つのdelete []呼び出しから発生します。

于 2012-07-24T06:33:49.577 に答える
1

5 つのノードの完全な配列が new によって作成されます。これで問題ありません。しかし、渡すポインタはset_Link()このメモリ ブロック内のどこかを指しているため、(a) ヒープ マネージャはデストラクタが呼び出したときにそれらを処理する方法を知りません。delete Link;(b) 知っていたとしても、それらは複数回削除されます。 5 つのオブジェクトを削除します。

delete注:経由で取得したもののみが必要ですnew

于 2012-07-24T06:37:21.227 に答える