【问题标题】:Will there be a memory leak in this Linked list这个链表会不会有内存泄漏
【发布时间】:2021-03-31 16:37:36
【问题描述】:

嗨,目前我一直在磨练我在数据结构方面的技能,以便我可以成为一名优秀的游戏开发人员,我正在学习链表并制作了一个链表程序,其中包含插入、删除和递归插入以及反转链表你能伙计们告诉我我在这里清除分配的内存使用新的运算符正确创建,我得到了所需的输出,但我担心内存泄漏。 ...请温柔瞄准 还在学习中。

class Node
{
    int data;
    Node *Next;

public:
    int GetData()
    {
        return data;
    }
    void SetData(int Data)
    {
        data = Data;
    }

    Node *GetNext()
    {
        return Next;
    }

    void SetNext(Node *next)
    {
        Next = next;
    }
};

void Insert(Node **Head, int x)
{
    Node *temp = new Node();

    temp->SetData(x);
    temp->SetNext(*Head);

    *Head = temp;
}

void InsertAt(Node **Head, int x, int n)
{
    if (n == 0)
    {
        std::cout << "The Given data at 'n' cannot be assigned to null\n";
    }

    Node *temp = new Node();
    temp->SetData(x);
    if (n == 1)
    {
        temp->SetNext(nullptr);
        *Head = temp;
        return;
    }

    Node *temp2 = *Head;
    if (Head == nullptr)
    {
        std::cout << "The Given data cannot be assigned to null\n";
    }

    for (int i = 0; i < n - 2; i++)
    {
        temp2 = temp2->GetNext();
    }

    temp->SetNext(temp2->GetNext());
    temp2->SetNext(temp);
}

void AppendList(Node **Head, int Data)
{
    Node *temp = new Node();

    Node *LastNode = *Head;

    temp->SetData(Data);
    temp->SetNext(nullptr);

    if (*Head == nullptr)
    {
        *Head = temp;
        return;
    }
    // else Traverse till last node.

    while (LastNode->GetNext() != nullptr)
    {
        LastNode = LastNode->GetNext();
    }
    LastNode->SetNext(temp);
}

void DeleteNode(Node **Head, int n)
{
    Node *temp = *Head;

    if (n == 1)
    {
        *Head = temp->GetNext();
        std::cout << "\nAfter Deletion of Head Node\n";
        return;
    }

    for (int i = 0; i < n - 2; i++)
    {
        temp = temp->GetNext();
    }
    Node *temp2 = temp->GetNext();
    temp->SetNext(temp2->GetNext());
    std::cout << "After Deletion of Node\n";
}

Node *ReverseList(Node *Head)
{
    Node *Current, *Prev, *next;

    Current = Head;
    Prev = nullptr;
    while (Current != nullptr)
    {
        next = Current->GetNext();
        Current->SetNext(Prev);
        Prev = Current;
        Current = next;
    }
    Head = Prev;
    return Head;
}

int LinkedList_Count(Node *Head)
{
    int count = 0;

    Node *Current = Head;
    while (Current != nullptr)
    {
        count++;
        Current = Current->GetNext();
    }
    std::cout << "Number of Elements: " << count;
    return count;
}

void PrintList(Node *Head)
{
    std::cout << "Data list : ";

    while (Head != nullptr)
    {
        std::cout << " " << Head->GetData();
        Head = Head->GetNext();
    }
    std::cout << "\n";
}

//Print Listed using Recursion
void Recursion_Print(Node *Head)
{
    if (Head == nullptr)
    {
        return;
    }

    std::cout << ' ' << Head->GetData(); //comment to Do Reverse the Linked list
    Recursion_Print(Head->GetNext());
    //std::cout << ' ' << Head->GetData();//unComment to Reverse the linked List recursively
}

Node *RecursiveRevList(Node *Head)
{
    Node *temp;
    if (Head->GetNext() == nullptr)
    {
        temp = Head;
        return temp;
    }
    temp = RecursiveRevList(Head->GetNext());
    Head->GetNext()->SetNext(Head);
    Head->SetNext(nullptr);
    return temp;
}
void RunList()
{
    Node *Head = NULL;

    //AppendList(&Head, 16);
    Insert(&Head, 6);
    Insert(&Head, 7);
    Insert(&Head, 8);
    InsertAt(&Head, 18, 2);
    std::cout << "Data list : \n";
    Recursion_Print(Head);
    std::cout << '\n';
    LinkedList_Count(Head);
    DeleteNode(&Head, 1);
    //Head = ReverseList(Head);
    Head = RecursiveRevList(Head);
    PrintList(Head);
    LinkedList_Count(Head);
    delete Head;
}

【问题讨论】:

  • 您肯定有泄漏,因为您从不释放内存,也没有使用会自动释放内存的智能指针。特别是您的 DeleteNode 从列表中分离一个节点但从不删除它。
  • 检查是否没有内存泄漏的最佳方法是编写大量测试并在 valgrind 等泄漏检测工具下运行它们。仅通过查看代码很难检测到内存泄漏,尤其是如果它不符合 RAII 原则。
  • 另见this C++ reference,了解standard containersC++ rule of five。使用至少使用g++ -Wall -Wextra -g 调用的GCC 进行编译。从现有的开源 C++ 项目中汲取灵感(例如fishRefPerSysninja...)
  • 无关,更多的是个人反思,但你用来学习 C++ 的资源或老师可能在教授 C++ 方面做得不好。您清楚地知道类,那么为什么不将类用于列表本身呢?使所有全局函数成为例如的成员函数List 类?
  • 链表是我会使用new 的少数几个地方之一,特别是如果我知道链表会长到足以威胁堆栈溢出。在这种情况下,已经存在递归迭代,所以不妨使用unique_ptr。总的来说,这里有一个关于 C++ 智能指针的精彩演示:Leak-Freedom in C++... By Default. 如果我没有混淆演示,我相信这是 Sutter 先生使用链表作为示例的那个。

标签: c++


【解决方案1】:

您正在编写 C 风格的代码;在 C++ 中,您应该 avoid explicit calls to new。您的示例是 far too long to rewrite,但这是一个非常小的开始:

#include <memory>
class Node
{
    int data;
    std::shared_ptr<Node> Next;

// ...
void Insert(std::shared_ptr<Node>& Head, int x)
{
    auto temp = std::make_shared<Node>();
    // ...
}

(请注意,std::unique_ptr 可能是比 std::shared_ptr 更好的选择,但这会导致复制 Node 的复杂性,而您现在“很高兴”没有意识到这一点。)

而且,在实践中,您应该真正使用std::list(在您的情况下为std::list&lt;int&gt;),而不是自己编写。一旦你熟练使用std::list(以及像std::vector 这样的朋友),你将能够更好地“自己动手”。

【讨论】:

  • @TricksterRazor Ðаn 的观点是有效的。归结为手动内存管理不是基本的。这是一项中高级技能,也是编程中最难做到的事情之一。即使是专家,也请按照专家的做法:极少使用它。
【解决方案2】:

正如许多有学问的人在 cmets 中指出的那样,您的程序存在内存泄漏。当您删除节点时,您实际上并没有释放分配的内存位置。正确的方法?使用delete从程序中释放内存。

我建议您根据经验学习它,在使用 C 或 C++ 编程时,如果您在程序中的某处分配动态内存,那么您肯定会有一些删除方法,您应该使用free()delete 从堆中释放内存。

这里有一些资源可能会对您有所帮助。

【讨论】:

猜你喜欢
  • 2016-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-20
  • 1970-01-01
  • 2022-06-13
  • 2012-06-01
  • 1970-01-01
相关资源
最近更新 更多