7

リンクリストを作成していますが、構造体のデストラクタ(ノード構造体)がそれ自体を削除するだけで、副作用が発生しないようにする必要があります。次のように、リストのデストラクタがそれ自体でノードデストラクタを繰り返し呼び出す(次のノードを一時的に保存する)ようにします。

//my list class has first and last pointers
//and my nodes each have a pointer to the previous and next
//node
DoublyLinkedList::~DoublyLinkedList
{
    Node *temp = first();

    while (temp->next() != NULL)
    {
        delete temp;
        temp = temp->next();
    }
}

したがって、これは私のノードデストラクタになります。

Node::~Node
{
   delete this;
}

これは、特にこのコンテキストでは受け入れられますか?

4

8 に答える 8

17

ノードデストラクタが呼び出されている場合は、すでに削除中です。したがって、ノードデストラクタ内では削除は意味がありません。

また、これは間違っています:

while (temp->next() != NULL)
{
     delete temp;
     temp = temp->next();
}

代わりに、temp-> next()を一時変数に入れる必要があります。それ以外の場合は、削除されたメモリにアクセスしています。

だからもっとこのように:

DoublyLinkedList::~DoublyLinkedList
{
  Node *temp = first();
  while (temp != NULL)
  {
       Node *temp2 = temp->next();
       delete temp;
       temp = temp2;
  }
}
于 2009-08-11T01:34:06.290 に答える
4

delete thisいいえ、デストラクタからではいけません。デストラクタは、deleteステートメントが原因で呼び出されます(またはスコープ外になります)。これにより、何らかのクラッシュが発生する可能性があります。

DoublyLinkedListdesturctorにもいくつか問題があります。1つは、tempを削除し、削除後にtempにアクセスすることです。次に、コードはリンクリストの最後の要素を実際には削除しません。

于 2009-08-11T01:37:46.210 に答える
4

次の行の2行目は、解放されたメモリに明確にアクセスするため、現在、コードによってアクセス違反が発生します。

delete temp;
temp = temp->next();

構造を再帰的に削除する場合は、次のようにします。

DoublyLinkedList::~DoublyLinkedList
{
    Node *temp = first();
    delete temp;
}

Node::~Node
{
   if(this->next() != NULL) delete this->next();
}
于 2009-08-11T01:40:31.650 に答える
2

何よりもまず、二重にリンクされたリストを理解するために、これがあなたに割り当てられた宿題であることを本当に願っています。それ以外の場合は、の代わりにこれを使用する理由はありませんstd::list。これが邪魔にならないように:

いいえ、 dtorは削除された状態のdelete thisときに呼び出されるため、dtorでは常に間違っています。this

また、

delete temp;
temp = temp->next();

temp->next()ちなみに動作する可能性がありますが、アクセスしようとした場所tempはすでに削除されているため、間違いなく間違っています。そのため、メンバー関数を呼び出す必要があります。そうすることで、いわゆる「未定義動作」が呼び出されます。(要するに:それはあなたが望むことをするかもしれませんが、それはいつもまたは散発的に、あるいは13日の金曜日が新月と衝突するときだけ失敗するかもしれません。それはまたあなたに非常に厄介な鼻の悪魔を呼び起こすかもしれません。)

ノードのdtorで次のノードを削除することで、両方の問題を解決できることに注意してください。

Node::~Node()
{
   delete next();
}

そうすれば、リストのdtorも非常に簡単になります。

DoublyLinkedList::~DoublyLinkedList()
{
    delete first();
}

私には、これはdtorが発明されたもののように思われるので、最近は誰も独自のリンクリストタイプを作成する必要がないという事実を除いて、これはあなたの問題に対するC++ソリューションのようです。

于 2009-08-11T08:57:15.647 に答える
1

これを削除します。現在のオブジェクトのデストラクタを呼び出します。その場合、呼び出している場合はこれを削除してください。デストラクタでは、クラッシュするまでデストラクタが無限に呼び出されます。

于 2009-08-11T01:37:46.880 に答える
0

上記のコードは、Node ::〜Node()を2回呼び出します。("deletetemp"およびNode::〜Node())

Node ::〜Node()は「deletethis」を呼び出さないでください(そうしないとプログラムがクラッシュします)

ps。コードのwhileループは機能しません。無効なポインタを逆参照します。最初にtemp->nextの値をコピーしてから、tempポインタを破棄する必要があります。

于 2009-08-11T01:37:18.847 に答える
0

一般に、デストラクタは、オブジェクトに特別に割り当てられたメモリを削除(またはCまたはmallocを使用している場合は解放)することだけを心配する必要があります。オブジェクトへのポインタの削除は常にOSによって管理され、その部分について心配する必要はありません。

覚えておく価値のあることの1つは、構築時に、最初にオブジェクトを作成し(制御フローがコンストラクターの本体に入るときに)、次にオブジェクトを内部に作成することです。破棄の場合は、逆に行う必要があります。最初に外部オブジェクトを削除すると、内部ポインタにアクセスしてそれらを削除する方法がなくなるためです。代わりに、デストラクタを使用して内部オブジェクトを削除すると、制御フローがデストラクタから外れたときに、OSが実際のメモリの解放を管理します。

ちなみに、サブクラス化でも同じようなことが起こります。クラスAとクラスB:public Aがある場合、新しいB()を実行すると、Aコンストラクターが最初に実行され、次にBのコンストラクターが実行されます。破壊されると、Bのデストラクタが最初に実行され、次にAが実行されます。ただし、これについて心配する必要はないと確信しています。C++が自動的に処理します。したがって、スーパークラスでdeleteを呼び出す方法を見つけようとしないでください。

于 2009-08-11T01:44:30.287 に答える
0

両方を行うべきではありません。

これ

DoublyLinkedList::~DoublyLinkedList
{
    Node *temp = first();
    while (temp->next() != NULL)
    {
        delete temp;
        temp = temp->next();
    }
}

未定義の動作が発生します-ヒープに戻ったメモリにアクセスすることは許可されていません。代わりに、次のようにする必要があります。

DoublyLinkedList::~DoublyLinkedList
{
    Node *temp = first();
    while( temp != NULL)
    {
        Node* next = temp->next();
        delete temp;
        temp = next;
    }
}

呼び出すdelete thisと、いわゆるダブルフリーが発生し、未定義の動作も発生します。デストラクタは、ポインタメンバー変数に対してのみdeleteを呼び出す必要があり、。に対しては呼び出さないでthisください。delete this現在のオブジェクトの割り当てを解除するために他のメソッドから呼び出すことは合理的ですが、デストラクタからは合理的ではありません。

于 2009-08-11T09:05:00.343 に答える