3

リンクリストを実装しました。これは完全に正常に機能しますが、Nodeで動作するデストラクタを作成できないという表記を見たことがあります。そのため、ここではコードで実装されていません。

  1. ノードに動作するデストラクタを実装する必要があります
  2. リストのデストラクタですが、これは単純です。ノードクラスのデストラクタを使用します(ただし、これが必要です)。
  3. リストをノードにとって使いやすいものにして、getNext()を使用する必要がないようにしますが、自分で処理できると思います(方法はわかりませんが、わかります)。

コードを見てください。それは完全に問題ありません。コピーすれば機能します。

#include <cstdio>
#include <cmath>
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;

class Node {
public:
    Node(Node* next, int wrt) {
        this->next = next;
        this->wrt = wrt;
    }

    Node(const Node& obiekt) {
        this->wrt = obiekt.wrt;
        this->next = obiekt.next;
    }
    ~Node() {}

    void show() {
        cout << this->wrt << endl;
    }

    int getWrt(){
        return this->wrt;
    }

    Node* getNext(){
        return this->next;
    }

    void setNext(Node* node){
        this->next = node;
    }

 private:
    Node* next;
    int wrt;
};

class List{
public:
    List(int wrt){
        this->root = new Node(NULL, wrt);
    }

    List(const List& obiekt){
        memcpy(&this->root,&obiekt.root,sizeof(int));
        Node* el = obiekt.root->getNext();
        Node* curr = this->root;
        Node* next;
        while(el != NULL){
            memcpy(&next,&el,sizeof(int));
            curr->setNext(next);
            curr = next;
            next = curr->getNext();
            el = el->getNext();
    /*      curr->show();
            next->show();
            el->show(); */
        }
    }

    void add(int wrt){
        Node* node = new Node(NULL, wrt);
        Node* el = this->root;
        while(el->getNext() != NULL){
            //el->show();
            el = el->getNext();
        }
        el->setNext(node);
    }

    void remove(int index){
        Node* el = this->root;
        if(index == 0){
             //deleting old one
             this->root = this->root->getNext();
        }
        else{
            int i  = 0;
            while(el != NULL && i < index - 1){
            //  el->show();
                el = el->getNext();
                i++;
            }
            if(el!=NULL){
                Node* toRem = el->getNext();
                Node* newNext = toRem->getNext();
                el->setNext(newNext);
                //deleteing old one
            }
        }
    }

    void show(){
        Node* el = this->root;
        while(el != NULL){
            el->show();
            el = el->getNext();
        }
    }

    ~List(){}

private:
    Node* root;
};

int main(){
    List* l = new List(1); //first list
    l->add(2);
    l->add(3);
    l->show();
    cout << endl;

    List* lala = new List(*l); //lala is second list created by copy cosntructor
    lala->show();
    cout << endl;

    lala->add(4);
    lala->remove(0);
    lala->show();

    return 0;
}
4

3 に答える 3

3

のデストラクタの実装から始めることをお勧めしますList。を使用してメモリを動的に割り当てたので、 を使用してメモリをnew解放する必要がありますdelete。( を使用new[]した場合は になりますdelete[]):

~List()
{
    Node* currentNode = this->root; // initialize current node to root
    while (currentNode)
    {
        Node* nextNode = currentNode->getNext();    // get next node
        delete currentNode;                         // delete current
        currentNode = nextNode;                     // set current to "old" next
    }
}

適切なデストラクタを取得したら、コピー コンストラクタが正しいかどうかを試してください。

List* lala = new List(*l);
delete l; // delete list that was used to create copy, shouldn't affect copy

コピー コンストラクターが間違っていることがわかり、アプリケーションがクラッシュする原因にもなります。なんで?コピー コンストラクターの目的は、既存のオブジェクトのコピーとして新しいオブジェクトを作成することです。コピー コンストラクターは、sizeof(Node*)等しいと仮定してポインターをコピーするだけsizeof(int)です。次のようになります。

List(const List& list)
{
    // if empty list is being copied:
    if (!list.root)
    {
        this->root = NULL;
        return;
    }

    // create new root:
    this->root = new Node(NULL, list.root->getWrt());

    Node* list_currentNode = list.root;
    Node* this_currentNode = this->root;
    while (list_currentNode->getNext())
    {
        // create new successor:
        Node* newNode = new Node(NULL, list_currentNode->getNext()->getWrt());
        this_currentNode->setNext(newNode);
        this_currentNode = this_currentNode->getNext();
        list_currentNode = list_currentNode->getNext();
    }
}

removeまた、一部のノードへの参照を「削除」しますが、このノードが存在するメモリを解放しないため、関数は間違っています。deleteこのメモリを解放するために呼び出す必要があります。

「ノードに機能するデストラクタを実装する必要があります」 - いいえ、必要ありません。ノード自体はメモリを割り当てないため、メモリを解放するべきではありません。Node* nextノードは、保存されているメモリの破壊やクリーニングの責任を負うべきではありませんNode.js のデストラクタやコピー コンストラクタを実装しないでください。これも読みたい: The Rule of Three?

「getNext() を使用する必要がないように、List を Node に適したものにします」 - Node クラス内で言いたいことclass Listは、friendとおりです。

class Node
{
    friend class List; // <-- that's it

これらの 5 つのヘッダーのうち、コードに含めるヘッダーは 1 つだけであることに注意してください<iostream>using namespace std;また、ファイルの先頭に書き込むことは、一部の型の名前があいまいになる可能性があるため、悪い習慣と見なされることに注意してください。小さなスコープ内で賢く使用するか、std::代わりにプレフィックスを使用してください。

于 2012-05-26T21:53:56.237 に答える
1

リンクリストデストラクタはdelete、リンクリストへの以前に割り当てられたポインタで使用される場合、またはリンクリスト変数がスコープ外になる場合(たとえば、関数から戻るときにローカル変数が破棄される場合)に呼び出されます。

リンクリストのデストラクタは、以前にノード用に予約したメモリを解放する責任があります(つまり、add操作を使用します)。したがって、基本的には、ノードのリストをトラバースして、delete各ノードに操作を適用する必要があります。ちょっとしたコツがあります。ノードを削除しようとしているときは、次の要素へのポインターを失わないように注意する必要があります(ノードが削除されても、nextメンバーがまだ有効であるかどうかはわかりません)。

于 2012-05-26T21:01:31.973 に答える