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

时间:2016-04-13 08:21:02

标签: c++ linked-list

我会提前为您寻求帮助而道歉并道歉。我真的不配任何方式。我也为我所知道的是我的草率代码道歉。我不想成为那个的家伙,但我真的很难过我该做什么。

到目前为止,这是故事:

list.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;
}

driver.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_front\n";
    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 end\n";
    cout << "\n----------------------------------\n";
    printList(partsList);

    // test pop-back
    cout << "\n----------------------------------\n";
    cout << "\nRemove last node from the list\n";
    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 nodes\n";
    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_back\n";
    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_front\n";
    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 list\n";
    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();
}

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

谢谢。从内心深处。

2 个答案:

答案 0 :(得分:1)

Thomasz&#39;答案是对的,只是一些额外的提示:

无论您将第一个或最后一个设置为nullptr,也可以为另一个设置:

first = last = nullptr;

push_back无法工作,如果列表为空,则最后是nullptr本身。试试这个:

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

Node类应该是列表类的内部细节,否则你允许在外部修改列表,而List不知道它!使Node成为一个内部类,并更改List的公共接口,使其在以前有Node *的任何地方处理Book *。然后创建和删除List函数中的节点 - 并且不要从Node的析构函数中删除Book。但是,您仍然可以使用Node类来迭代List,因此它将对应于:: std :: list&#39;迭代器。

你可以直接分配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;
}

答案 1 :(得分:0)

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

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所有,但不是{0}}。此外,最后一个元素将始终泄漏。