【问题标题】:Do I need to delete a dynamically allocated object in Singly Linked List?我需要删除单链表中动态分配的对象吗?
【发布时间】:2021-06-07 04:28:22
【问题描述】:

我目前正在学习链接列表,并且已经使用 Append 和 Prepend 方法实现了一个单链表,其中我使用“new”运算符在堆上分配了 Node 类型的对象。我是否需要使用“删除”在堆上释放对象,如果需要,我该怎么做? 这是我的代码:-

class List
{
private:
    class Node
    {
    public:
        int data;
        Node* next;
        Node()
        {
            data = 0;
            next = NULL;
        }
        Node(const int& data)
        {
            this->data = data;
        }
    };

    Node* head;
public:
    List()
    {
        head = NULL;
    }
    void Append(const int&val);
    void Prepend(const int&val);
    void DisplayAll();
};

void List::Append(const int&val)
{
    Node* n = new Node(val); //dynamically allocated 
    if (head == NULL)
    {
        head = n;
        return;
    }
    Node* temp = NULL;
    temp = head;
    while (temp->next != NULL)
    {
        temp = temp->next;
    }
    temp->next = n;
}

void List::Prepend(const int&val)
{
    Node* node = new Node(val);//dynamically allocated 
    if (head == NULL)
    {
        head = node;
        return;
    }
    node->next = head;
    head = node;
}

void List::DisplayAll()
{
    Node* temp = head;
    while (temp != NULL)
    {
        std::cout << temp->data << ' ';
        temp = temp->next;
    }
}

【问题讨论】:

  • Any 如果不再需要动态分配的数据,则需要为deleted,否则会出现内存泄漏。这也包括您的节点。
  • 你可以编写一个析构函数(例如~Node() { ... })来为你做这件事。 (这将是确保班级自行清理的正确方法)例如~Node() { while (head) { Node *victim = head; head = head-&gt;next; delete victim; } }
  • 另外,如果你添加一个tail指针(例如Node *head, *tail;)并且总是让tail指向你列表中的最后一个节点,你可以在O(1)时间内append无需迭代。
  • 旁注:习惯于实现构造函数的初始化列表(不要与std::initializer_list混淆):List() : head(nullptr) { }。这比默认初始化+赋值更喜欢直接初始化,另外一些成员类型(常量、引用、不可赋值的)only 可以这样初始化。此外,您应该更喜欢 C++ keywords (nullptr) 而不是旧的(过时的?)C macros (NULL)。
  • 虽然适合学习,但请记住std::forward_list 已经在做同样的事情,你应该稍后使用它而不是重新发明的轮子。关于学习:下一步是将您的列表转换为模板,以便能够添加任意数据类型。

标签: c++ pointers linked-list c++17 singly-linked-list


【解决方案1】:

对于初学者来说这个构造函数

    Node(const int& data)
    {
        this->data = data;
    }

不初始化数据成员next。因此成员函数AppendPrepend 有一个错误

void List::Append(const int&val)
{
    Node* n = new Node(val); //dynamically allocated 
    if (head == NULL)
    {
        head = n;
        return;
    }
    //...

void List::Prepend(const int&val)
{
    Node* node = new Node(val);//dynamically allocated 
    if (head == NULL)
    {
        head = node;
        return;
    }
    //...

头节点的数据成员next有一个不确定的值。

你可以简单地声明类Node

struct Node
{
    int data;
    Node* next;
};

Node* head = nullptr;

在这种情况下,例如函数 Prepend 看起来像

void List::Prepend( const int &val )
{
    head = new Node { val, head };
}

构造函数看起来像

List() = default;

要释放列表中所有已分配的节点,您可以再编写两个成员函数clear 和调用函数clear 的析构函数。

例如

#include <functional>

//...

class List
{
//...
public:
    void clear()
    {
        while ( head ) delete std::exchange( head, head->next );
    }

    ~List() { clear(); }
    //...

此外,您至少应该编写一个复制构造函数和复制赋值运算符,或者将它们定义为已删除。

【讨论】:

    猜你喜欢
    • 2018-01-13
    • 1970-01-01
    • 2011-07-23
    • 2012-11-06
    • 1970-01-01
    • 2021-04-03
    • 2011-05-02
    • 1970-01-01
    • 2013-08-26
    相关资源
    最近更新 更多