【问题标题】:List destructor in C++C ++中的列表析构函数
【发布时间】:2012-06-01 22:19:39
【问题描述】:

我刚刚实现了链接列表。它工作得非常好,但甚至很难我已经看到了我无法在 Node 上创建工作析构函数的符号,这就是它在代码中未实现的原因。

  1. 我需要在节点上实现工作析构函数
  2. List 的析构函数,但这个很简单,我将只使用 Node 类的析构函数(但我需要这个)。
  3. 使 List 对 Node 友好,这样我就不必使用 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;
}

【问题讨论】:

  • 你不应该是memcpy-ing Nodes,因为它们不是 POD 对象。
  • 我将首先修复缩进并将变量从 nn2wrtlala 重命名为有意义的名称。还要去掉using namespace std;——把它放在文件的开头是不好的做法。
  • 不,这不是家庭作业。我尝试刷新我的 c++。 n 已被评论,我现在将其删除。
  • 你所有的对象都是动态分配的,你没有在任何地方调用delete。你的析构函数永远不会运行...
  • 另一个小修复,在 C++ 中,标题是 &lt;cstdio&gt;&lt;cstring&gt; 而不是 &lt;stdio.h&gt;&lt;string.h&gt;(因为它们在 C 中被调用)。

标签: c++ linked-list destructor


【解决方案1】:

我建议你从实现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 本身不分配任何内存,因此它不应该释放任何内存。节点不应该负责销毁Node* next,也不应该清理存储它的内存。不要实现 Node 的析构函数或复制构造函数。您还想阅读以下内容:What is The Rule of Three?

“使 List 对 Node 友好,这样我就不必使用 getNext()” - 你想在 Node 类中说,class List 是它的friend:

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

请注意,在您包含代码的这 5 个标头中,只需要一个:&lt;iostream&gt;。 另请注意,在文件开头写using namespace std; 被认为是不好的做法,因为它可能会导致您的某些类型的名称变得模棱两可。在小范围内明智地使用它或改用std:: 前缀。

【讨论】:

  • 实际上,将Node 定义为List 中的内部私有结构会更好。然后你可以避免使用friend
  • 非常感谢您与我分享这些知识。顺便说一句,您向我介绍了它,我认为您可能会成为一名好老师(学术)。太好了。
  • @RobertKilar:很高兴它对你有所帮助:)
【解决方案2】:

delete 与先前分配的指向链表的指针一起使用或链表变量超出范围时(例如,从函数返回时破坏局部变量),将调用链表析构函数.

链表的析构函数应该负责释放您之前为节点保留的内存(即,使用add 操作)。因此,基本上,您需要遍历节点列表并对每个节点应用 delete 操作。有一个小技巧:当你要删除一个节点时,你必须小心不要丢失指向下一个元素的指针(当一个节点被删除时,你不能确定next 成员是否仍然有效)。

【讨论】:

    【解决方案3】:

    如果你想为你的节点创建一个析构函数,实际上应该很简单。

    这里是:

    class Node {
        private:
            int wrt;
            Node* next;
        public:
            Node(Node* next, int wrt) {
                this->next = next;
                this->wrt = wrt;
            }
    
            // Your desired destructor using recursion
            ~Node() {
                if ( next != NULL )
                    delete next;
            }
    };
    

    就这么简单:)

    基本上,在节点被删除之前,如果next不为空,我们就删除next,这将再次调用next的析构函数,如果next->next不为空,则再次调用析构函数。

    那么最后所有的节点都会被删除。

    递归处理了整个事情:)

    【讨论】:

    • 我认为由于递归析构函数调用,这将导致足够大列表的堆栈溢出。
    猜你喜欢
    • 2018-03-27
    • 2020-10-07
    • 2016-09-09
    • 1970-01-01
    • 1970-01-01
    • 2012-07-28
    • 2011-03-09
    • 2014-12-20
    • 2015-08-03
    相关资源
    最近更新 更多