C++:链表析构函数内存泄漏



我会坦率地为请求您的帮助而道歉。我真的不配得到它。我也为我所知道的草率的代码道歉。我不想成为那个的人,但我真的很困惑我该怎么做。

到目前为止的情况如下:

列表.cpp

Node::Node()
{
    next = nullptr;
    book = nullptr;
}
Node::Node(Book* newBook)
{
    next = nullptr;
    book = newBook;
}
Node::~Node()
{
    if (next != nullptr)
    {
        delete book;
    }
}
Node* Node::getNextNode() const
{
    return next;
}
void Node::setNext(Node* newNext)
{
    if (newNext == nullptr)
    {
        next = nullptr;
    }
    else
    {
        next = newNext;
    }
}
Book* Node::getBook() const
{
    return book;
}
List::List()
{
    first = nullptr;
    last = nullptr;
    numNodes = 0;
}
List::~List()
{
    Node* tempNode = first;
    first = first->getNextNode();
    while (first != nullptr)
    {
        delete tempNode;
        numNodes--;
        tempNode = first;
        first = first->getNextNode();
    }
    last = nullptr;
}
void List::push_front(Node* newNode)
{
    Node* tempNode = first;
    newNode->setNext(tempNode);
    first = newNode;
    if (last == nullptr)
    {
        last = first;
    }
    numNodes++;
}
void List::push_back(Node* newNode)
{
    Node* tempNode = last;
    tempNode->setNext(newNode);
    last = newNode;
    if (first == nullptr)
    {
        first = last;
    }
    numNodes++;
}
Node* List::pop_front()
{
    if (first != nullptr)
    {
        Node* tempNode = first;
        if (tempNode->getNextNode() == nullptr)
        {
            numNodes--;
            return first;
        }
        if (first == last)
        {
            numNodes--;
            first = nullptr;
            return first;
        }
        first = first->getNextNode();
        numNodes--;
        return tempNode;
    }
    return nullptr;
}
Node* List::pop_back()
{
    if (last != nullptr)
    {
        Node* tempNode = first;
        if (first == last)
        {
            numNodes--;
            first = nullptr;
            return first;
        }
        if (tempNode->getNextNode() == nullptr)
        {
            numNodes--;
            return first;
        }
        while (tempNode->getNextNode()->getNextNode() != nullptr)
        {
            tempNode = tempNode->getNextNode();
        }
        last = tempNode;
        last->next = nullptr;
        numNodes--;
        return tempNode;
    }
    return nullptr;
}
Node* List::getFirst() const
{
    return first;
}
Node* List::getLast() const
{
    return last;
}

驱动程序.cpp

int main()
{
    // set up cout for displaying prices
    cout.setf(ios::fixed);
    cout.setf(ios::showpoint);
    cout.precision(2);
    // create a List object
    List partsList;
    cout << "nPart I: multiple node test: push_front and pop_frontn";
    cout << "n----------------------------------n";
    // build a List using push_front
    partsList.push_front(new Node(new Book("Fun With C++", "I. M. Codemann", 95.00)));
    partsList.push_front(new Node(new Book("Lousy Linked Lists", "B. A. Hacker", 74.90)));
    partsList.push_front(new Node(new Book("Programming Nuts", "R. U. Krazy", 85.25)));
    partsList.push_front(new Node(new Book("Silly Syntax", "Irma Coder", 30.15)));
    cout << "nThe original nodes in the List:n";
    printList(partsList);
    cout << "n----------------------------------n";
    // test push_front function
    cout << "nAdding to the front of the List:n";
    cout << "n----------------------------------n";
    partsList.push_front(new Node(new Book("Python's a Snake", "C. Rules", 65.45)));
    partsList.push_front(new Node(new Book("Programming Fables", "J. Aesop", 73.15)));
    printList(partsList);
    cout << "n----------------------------------n";
    // test pop-front
    cout << "nRemoving the first node from the list.n";
    cout << "n----------------------------------n";
    Node* item = partsList.pop_front();
    printList(partsList);
    if (item != NULL)
        delete item;
    cout << "n----------------------------------n";
    cout << "nPart Two: Push_back and pop_back";
    // test push_back
    partsList.push_back(new Node(new Book("Coding Shortcuts", "B. Lazy", 110.25)));
    partsList.push_back(new Node(new Book("Famous Programmers I Know", "M. T. Set", 126.00)));
    cout << "nAdding two nodes at the endn";
    cout << "n----------------------------------n";
    printList(partsList);
    // test pop-back
    cout << "n----------------------------------n";
    cout << "nRemove last node from the listn";
    cout << "n----------------------------------n";
    item = partsList.pop_back();
    printList(partsList);
    if (item != NULL)
        delete item;
    // delete all of the Nodes in the list
    cout << "nEmpty the list and delete all nodesn";
    while (partsList.getFirst() != nullptr)
    {
        Node * t = partsList.pop_front();
        delete t;
    }
    printList(partsList);
    // Test Push_front and pop_back - do they handle special case
    cout << "nTesting special case handling for push_front and pop_backn";
    partsList.push_front(new Node(new Book("Test Book 1", "nobody", 1.25)));
    Node* t = partsList.pop_back();
    cout << "nThe Node just removed contains " << t->getBook()->getTitle() << endl;
    delete t;
    // Test push_back and pop_front - do they handle special cases
    cout << "nTesting special case handling for push_back and pop_frontn";
    partsList.push_back(new Node(new Book("Test Book 2", "nobody", 1.25)));
    t = partsList.pop_front();
    cout << "nThe Node just removed contains " << t->getBook()->getTitle() << endl;
    delete t;
    // Is the list now empty
    cout << "nThe list should now be empty...n";
    printList(partsList);
    cout << "n-------------------------------------------n";
    cout << "nEnd of Test";
    cout << "n-------------------------------------------n";
    system("PAUSE");
    return 0;
}
void printList(const List& theList)
{
    if (theList.getFirst() == nullptr) // if the list is empty
        cout << "nempty listn";
    else
    {
        Node* t = theList.getFirst();
        while (t != NULL)
        {
            Book* bp = t->getBook();
            cout << bp->getTitle() << ' ';
            cout << bp->getAuthor() << ' ';
            cout << "$" << bp->getPrice() << endl;
            t = t->getNextNode();
        }
    }
}
void printFirstNode(List theList)
{
    Node* t = theList.getFirst();
    Book* bp = t->getBook();
    cout << bp->getTitle() << ' ';
    cout << bp->getAuthor() << ' ';
    cout << "$" << bp->getPrice() << endl;
    t = t->getNextNode();
}

好吧,到目前为止,我的链接列表似乎运行得相对顺利。该程序仅在最后一次printList函数调用的hometretch处引发异常(Proj_02.exe中0x00E5654B处的未处理异常:0xC0000005:读取位置0xDDDDDF1的访问冲突。)。我真的不知道为什么会抛出这个异常,列表应该是完全空的。所以,我必须羞愧地垂下头。我应该怎么做才能解决这个问题?

谢谢。发自内心。

托马兹的回答到目前为止是正确的,只是一些额外的提示:

无论您在哪里将first或last中的一个设置为nullptr,也可以为另一个设置:

first = last = nullptr;

push_back不起作用,如果列表是空的,那么最后一个是nullptr本身。试试这个:

if(!last)
{
    first = last = newNode;
}
else
{
    last->setNext(newNode);
    last = newNode;
}
++numNodes;

Node类应该是列表类的内部细节,否则您可以在列表不知情的情况下从外部修改列表!将Node设为内部类,并更改List的公共接口,使其在以前有Node*的地方处理Book*。然后在列表的函数中创建和删除节点,不要从节点的析构函数中删除Book。不过,您仍然可以使用Node类来迭代List,因此它将对应于:std::List的迭代器。

你可以直接分配newNext:即使它是一个空指针,next仍然会被分配这个,所以检查是多余的:

void Node::setNext(Node* newNext)
{
    // if (newNext == nullptr)
    //{
    //    next = nullptr;
    //}
    //else
    //{
        next = newNext;
    //}
}

我可以假设你写这份清单是为了学习吗?否则,您可能会使用STL中的::std::list。。。

我允许自己重写你的列表类,这样你就可以比较了。希望这能帮助你。。。

class List
{
public:
    List();
    ~List();
    class Node
    {
    public:
        Node const* getNext() const
        {
            return next;
        }
        Book* getBook() const
        {
            return book;
        }
    private:
        friend class List;
        Node(Book*);
        Node* next;
        Book* book;
    };
    void push_front(Book* book);
    void push_back(Book* book);
    Book* pop_front();
    Book* pop_back();
    Book* getFirst() const;
    Book* getLast() const;
    Node const* getFirstNode() const
    {
        return first;
    }
private:
    Node* first;
    Node* last;
    unsigned int numNodes;
};
List::Node::Node(Book* newBook)
        : next(nullptr), book(newBook)
{
}
List::List()
    : first(nullptr), last(nullptr), numNodes(0)
{
}
List::~List()
{
    while (first)
    {
        Node* tempNode = first;
        first = first->next;
        delete tempNode;
    }
}
void List::push_front(Book* book)
{
    Node* node = new Node(book);
    if (first)
    {
        node->next = first;
        first = node;
    }
    else
    {
        first = last = node;
    }
    ++numNodes;
}
void List::push_back(Book* book)
{
    Node* node = new Node(book);
    if (last)
    {
        last->next = node;
        last = node;
    }
    else
    {
        first = last = node;
    }
    ++numNodes;
}
Book* List::pop_front()
{
    Book* book = nullptr;
    if (first)
    {
        book = first->book;
        Node* tempNode = first;
        first = first->next;
        if (!first)
        {
            last = nullptr;
        }
        delete tempNode;
        --numNodes;
    }
    return book;
}
Book* List::pop_back()
{
    Book* book = nullptr;
    if (last)
    {
        book = last->book;
        Node* tempNode = first;
        if (first == last)
        {
            first = last = nullptr;
        }
        else
        {
            while(tempNode->next != last)
            {
                tempNode = tempNode->next;
            }
            delete last;
            last = tempNode;
            last->next = 0;
        }
        --numNodes;
    }
    return book;
}
Book* List::getFirst() const
{
    return first ? first->book : nullptr;
}
Book* List::getLast() const
{
    return last ? last->book : nullptr;
}

您的崩溃似乎与以下代码部分有关:

Node* List::pop_front()
{
    if (first != nullptr)
    {
        Node* tempNode = first;
        if (tempNode->getNextNode() == nullptr)
        {
            numNodes--;
            return first;
        }
        if (first == last)
        {
            numNodes--;
            first = nullptr;
            return first;
        }
        first = first->getNextNode();
        numNodes--;
        return tempNode;
    }
    return nullptr;
}

两种情况:

    if (tempNode->getNextNode() == nullptr)
    {
        numNodes--;
        return first;
    }
    if (first == last)
    {
        numNodes--;
        first = nullptr;
        return first;
    }

似乎服务于单个元素列表(first == lastnext == nullptr)的目的。所以,第一个应该是:

    if (tempNode->getNextNode() == nullptr)
    {
        numNodes--;
        first = nullptr;
        return tempNode;
    }

此外:

Node::Node(Book* newBook)
{
    next = nullptr;
    book = newBook;
}
Node::~Node()
{
    if (next != nullptr)
    {
        delete book;
    }
}

在调用的情况下是100%泄漏,如:

new Node(new Book("Test Book 1", "nobody", 1.25))

由于next仍然是nullptr,并且book应该由Node拥有,但不是。此外,最后一个滤芯总是会泄漏。

最新更新