链表中的C ++析构函数

时间:2018-10-19 14:43:37

标签: c++ linked-list

我已经使用c ++中的链接列表构建了一个堆栈,但是有人告诉我,整个事情一文不值,因为我的析构函数不能高效地完成其工作,所以有人可以告诉我如何为该代码构建析构函数。据我了解,构造函数的工作是删除未使用的内存,我提到的析构函数还有其他功能吗? 任何帮助将不胜感激。

#include <iostream>
#include <string>
#include <limits>
using namespace std;

class Stack
{
private:
    struct node
    {
        int data;
        node* next;

        node()
        {
          int data = 0;
          next = nullptr;
        }

    };
node* top;
public:
    Stack()
    {
        top = nullptr;
    }
    ~Stack()
    {
       delete top;
    }
 void push(int n)
 {
    node* temp = new node;
    temp->data = n;
    temp->next = top;
    top = temp; 
 }

    int pop()
    {
        node* temp = top;
        top = top->next;
        return temp->data;
    }

    int peek()
    {
        return top-> data;
    }

    bool isEmpty()
    {
        return top == 0;
    }
};

int main()
{
    Stack stack;

    std::string command;

    while (true)
    {
        std::cout << "stack>";
        std::cin >> command;
        try
        {
            if (command == "pop")
            {
                if (stack.isEmpty())
                {
                    throw std::runtime_error("error: stack is empty");
                }
                 std::cout << stack.pop() << std::endl;
            }

            else if (command == "push")
            {
                int n;
                if (!(std::cin >> n))
                {
                    throw std::runtime_error("error: not a number");
                }
                stack.push(n);
            }

            else if (command == "peek")
            {
                if (stack.isEmpty())
                {
                     throw std::runtime_error("error: stack is empty");
                }
                std::cout << stack.peek() << std::endl;
            }

             else if (command == "end")
            {
                 while (!(stack.isEmpty()))
                 {
                    std::cout << stack.pop() << std::endl;
                 }
                return 0;
            }
            else
            {
                throw std::runtime_error("error: invalid command");
            }
        }
        catch (std::runtime_error& e)
        {
            std::cin.clear();
            std::cin.ignore(numeric_limits<streamsize>::max(), '\n');
            std::cerr << std::endl << e.what() << std::endl;
        }
    }
    return 0;
}

4 个答案:

答案 0 :(得分:1)

您在Stack::pop()方法中发生内存泄漏,而您的Stack()析构函数仅删除top,因此,如果元素多于1个,则还会有另一个泄漏。处理动态分配的内存时,最好使用智能指针:

class Stack
{
    struct node;
    using node_ptr = std::unique_ptr<node>;
private:
    struct node
    {
        int data;
        node_ptr next;

        node(int n, node_ptr nxt) : data(n), next( std::move(nxt) )
        { // your old ctor has a bug, you "initialized" local variable
        }
    };

    node_ptr top;
    Stack() = default;
    ~Stack()
    {
         while(top)
             top = std::move( top->next );
    }

    int pop()
    {
       node_ptr temp = std::move(top);
       top = std::move(temp->next);
       return temp->data;
    }

    void push(int n)
    {
        top = std::make_unique<node>(n,std::move(top));
    }

    int peek() const
    {
        return top->data;
    }

    bool isEmpty() const
    {
       return !top;
    }
};

您的代码变得更小,更容易理解,并且没有以前的泄漏。您不必提供显式的Stack析构函数,但是效率低下(执行递归调用,但仍然正确)。提供的析构函数更加高效。

答案 1 :(得分:0)

您有一个这样的列表:

top---->node->node->node->node->...

Stack的析构函数中,删除top指向的对象。您剩下的是:

              node->node->node->...

请注意,大多数节点尚未删除,并且由于不再指向它们,因此不再有删除它们的方法。这称为内存泄漏。

要修复析构函数,必须删除列表中的每个节点。提示:使用循环;复制下一个指针,删除当前节点,然后继续下一个指针。


析构函数不是堆栈泄漏的唯一地方。 pop无法删除顶级节点,然后再将其从列表中取消链接。

此外,分配或处理Stack对象将导致两个对象具有相同的列表,并因此尝试将其删除两次(分别在每个对象的析构函数中一次)。该行为将是不确定的。每当在析构函数中管理资源时,总是需要定义一个副本(并移动)构造函数和也要管理资源的赋值运算符。这称为3的规则(移动操作为5)。如果您不希望类是可复制的(或可移动的),则可以声明它们已删除。

拥有裸露的指针是一个糟糕的设计。更好的设计是使用std::unique_ptr

您的node构造函数使data成员未初始化。我认为您的堆栈不会读取默认的初始化节点,因此这可能不成问题,但是您可能对编写的构造函数有不同的期望。

答案 2 :(得分:0)

您需要为while链接列表分配内存:

~Stack()
    {
        while(top)
        {
            struct node* curr = top;
            top = top->next;
            delete curr;
        }
        top = nullptr;
    }

答案 3 :(得分:0)

您仅删除顶部元素。

尝试将~node() { delete next; }添加到您的node结构中。

并确保其NULL终止,以使其停止!