【问题标题】:Memory Leak in Custom Linked List C++自定义链表 C++ 中的内存泄漏
【发布时间】:2017-11-12 04:36:15
【问题描述】:

对于我不能使用 STL 列表的作业,它必须是自定义列表。正如标题所述,即使我在节点\项目上调用删除,我也有内存泄漏。我将不胜感激。

列出来源

template <typename T>
class DLinkList
{
private:
    struct Node
    {
        T data;
        Node *nextNode;
        Node *prevNode;
        Node(T data, Node *nextNode = nullptr, Node *prevNode = nullptr)
        {
            this->data = data;
            this->nextNode = nextNode;
            this->prevNode = prevNode;
        }
        ~Node() { delete data; }
    };

    Node *head;
    Node *tail;

public:
    DLinkList();
    ~DLinkList();

    void push_back(T data);   
};

template <typename T>
inline void DLinkList<T>::push_back(T data)
{
    if (isEmpty())
    {
        head = new Node(data);
        tail = head;
    }
    else
    {
        tail->nextNode = new Node(data, nullptr, tail);
        tail = tail->nextNode;
    }
}

template <typename T>
DLinkList<T>::DLinkList()
{
    head = nullptr;
    tail = nullptr;
}

template <typename T>
DLinkList<T>::~DLinkList()
{
    Node *ptr = head;
    while (ptr->nextNode != nullptr)
    {
        Node *garbage = ptr;
        ptr = ptr->nextNode;
        delete garbage;
    }
}

Foo 类和 main

class Foo
{
public:
    Foo() { i = 0; d = 0.0; }
    Foo(int i, double d) { this->i = i; this->d = d; }

    int getInteger() { return i; }
    double getDouble() { return d; }

private:
    int i;
    double d;
};


int main()
{
    DLinkList<Foo*> f1;
    f1.push_back(new Foo());
    f1.push_back(new Foo(2, 5.5));

    cout << "1st Values: " << f1.at(0)->getInteger() << ", " << f1.at(0)->getDouble() << endl;
    cout << "2nd Values: " << f1.at(1)->getInteger() << ", " << f1.at(1)->getDouble() << endl;

    return 0;
}

来自 valgrind

==12125== 40 (24 direct, 16 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 3
==12125==    at 0x4C29203: operator new(unsigned long) (vg_replace_malloc.c:334)
==12125==    by 0x400FD8: DLinkList<Foo*>::push_back(Foo*) (DLinkList.hpp:138)
==12125==    by 0x400CF3: main (Source.cpp:28)

我不确定这里的记忆是如何丢失的,我想说这是因为它正在复制它而原始的正在丢失。如果是这种情况,我不知道如何处理。

再次感谢任何有助于理解这一点的帮助。我试图查看所有相关问题,但我没有看到任何涵盖此内容的内容,或者至少我不理解它。谢谢!

【问题讨论】:

  • 我的猜测是,这取决于您为T 使用的类型。也许Node 中的析构函数会有所帮助。
  • 我刚试过。调用数据删除,valgrind 显示 4 个分配,4 个释放 - 但我仍然有相同消息的泄漏。
  • @MasonR f1.~DLinkList(); -- 你为什么要这样做?一旦对象超出范围,就会自动调用对象的析构函数。您在这里所做的只是通过干扰 C++ 析构函数的工作方式而导致内存损坏。摆脱那条线,并修复你的类,使其具有正确的复制语义(只需将DLinkList 分配给另一个DLInkList,你的程序就很容易被破坏)。
  • @PaulMcKenzie 我删除了这条线,我知道它是自动的。至于使类可复制,如何解决这里的内存泄漏问题?
  • 一旦您执行以下操作,您将再次遇到内存泄漏和双重释放问题:DLinkList&lt;foo*&gt; f2 = f1; 在您填充f1 之后。其次,删除该行可能无法纠正所有内存泄漏,但确实解决了通过像这样显式调用析构函数而导致的内存损坏问题。

标签: c++ list memory-leaks valgrind


【解决方案1】:

鉴于 cmets 中指出的其他问题,例如显式调用 DLinkList 析构函数的错误用法,您在 main() 中执行此操作:

f1.push_back(new Foo());
f1.push_back(new Foo(2, 5.5));

您在这两行无法恢复的代码上创建了即时内存泄漏。您正在调用new,但您没有保存从new 返回的地址,以便您稍后可以为该地址调用delete

所以是main 必须管理这些动态分配的Foo 对象。像这样的:

Foo* p1 = new Foo();
Foo *p2 = new Foo(2, 5.5);
f1.push_back(p1);
f1.push_back(p2);
//...
delete p1;
delete p2;

这应该解决内存泄漏问题,但在当今的 C++ 时代,这是一种糟糕的编程实践。您很可能会使用

DLinkList<Foo>

并将Foo对象放在链表中,因此不需要在main中进行任何手动内存管理,或者使用智能指针并拥有智能指针的链表,即

DLinkList<std::unique_ptr<Foo>>

【讨论】:

  • 感谢您的回复。我通常会使用向量和列表,并通过一个简单的循环让 main 清理它。我已经尝试过第一种和第二种方式,但由于某种原因,它仍然存在泄漏。我没有尝试使用智能指针,因为我也不打算使用它们:(
  • 请参阅下面的答案以解释如何纠正内存泄漏。我仍然将这个标记为选择的答案,因为 PaulMcKenzie 提出了许多也导致内存泄漏的优点。谢谢保罗麦肯齐!
【解决方案2】:

好吧,我只是筋疲力尽,错过了最简单的事情。在与我创建的其他列表进行比较后,我意识到我的析构函数没有正确删除节点。

template <typename T>
DLinkList<T>::~DLinkList()
{
    Node *ptr = head;
    while (ptr != nullptr) // Not: ptr->nextNode
    {
        Node *garbage = ptr;
        ptr = ptr->nextNode;
        delete garbage;
    }
}

但我确实要感谢 PaulMcKenzie,这是一个很大的帮助,并且还指出 main 确实需要处理新调用的删除。我会投票给他并标记它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-13
    • 1970-01-01
    • 2017-08-24
    • 2021-05-19
    • 2021-08-21
    • 2017-09-26
    • 1970-01-01
    相关资源
    最近更新 更多