1

我刚刚实现了一个析构函数,我得到了一个“访问冲突读取位置”。我相信问题出在我的while循环中,但无法弄清楚。

下面是我的代码。如果需要引用我的列表类的任何其他部分,请告诉我。

谢谢!

List::List():first(NULL), last(NULL), nodeListTotal(0)
{
}    

List::~List()
{
    Node* currentNode = first;

    while( currentNode != 0 ) 
    {
        Node* temp = currentNode->getNext();
        delete currentNode;
        currentNode = temp;
    }

    first = 0;
}

这是我的整个 List 课程。我已经进行了建议的更改,删除了first = 0;并将 0 更改为nullptr

#include "Node.h"
#include <string>
using namespace std;

class List
{
    private:
        int nodeListTotal;
        Node* first;
        Node* last;

    public:
        //Constructor
        List();
        //Destructor
        ~List();
        //Copy-Constructor
        //List(const List& theList);
        //////Overloading Assignment Operator
        //List& operator=(const List& L);

        void push_back(Node*);
        void push_front(Node*);
        Node* pop_back();
        Node* pop_front();
        Node* getFirst() const;
        Node* getLast() const;
        int getListLength() const;
};

List::List():first(NULL), last(NULL), nodeListTotal(0)
{
}

// Destructor
List::~List()
{
    Node* currentNode = first;

    while( currentNode != nullptr ) 
    {
        Node* temp = currentNode->getNext();
        delete currentNode;
        currentNode = temp;
    }
}

// Copy-Constructor
//List::List(const List& theList)
//{
//  Node * tempPtr = new Node;
//  tempPtr = theList.first;
//  List(tempPtr);
//  
//  while (tempPtr != NULL)
//  {
//      Node * copyNode = new Node;
//      copyNode = tempPtr;
//      tempPtr = tempPtr->getNext();
//      nodeListTotal++;
//  }
//}

// Overloading Assignemnt Operator
//List& List::operator=(const List& L)
//{
//  List* overList;
//  Node* temp = L.first;
//  
//  while( temp != NULL ) {
//      overList->getLast();
//      temp = temp -> getNext();
//      
//      return *this;
//}

void List::push_back(Node* newNode)
{
    Node* temp = last;
    if (temp)
        temp->setNext(newNode);
    else
        first = newNode;

    last = newNode;
    nodeListTotal++; 
}

void List::push_front(Node* newNode)
{
    Node* temp = getFirst();
    newNode->setNext(temp);
    first = newNode;
    nodeListTotal++;

    if (!temp)
        last = first;
}

Node* List::pop_back()
{
    Node* old = last;
    if (first == last)
    {
        first = 0;
        last = 0;
    }
    else
    {
        Node* temp = first;

        for (int i = 0; i < (nodeListTotal - 1); i++)
        {
            temp = temp->getNext();
        }

        temp->setNext(NULL);

        last = temp;
    }

        nodeListTotal--;
        return old;
}

Node* List::pop_front()
{
    Node* temp = getFirst();
    first = temp->getNext();

    if (!first)
        last = 0;

    nodeListTotal--;

    return temp;
}

Node* List::getFirst() const
{
    return first;
}

Node* List::getLast() const
{
    return last;
}

int List::getListLength() const
{
    return nodeListTotal;
}

节点.h

#include <string>
using namespace std;

class Node
{
    private:
        string dataItem;
        string dataUnit;
        int unitTotal;
        Node* next;

    public:
        //Constructor
        Node();

        Node(int, string, string);

        string getDescription( )const; 
        void setDescription(string);

        string getQuantityName()const; 
        void setQuantityName(string);

        int getQuantityNumber()const; 
        void setQuantityNumber(int);

        Node* getNext( )const; 
        void setNext(Node*);
};

Node::Node(void):dataItem("None"), dataUnit("None"), unitTotal(0), next(NULL)
{
}

Node::Node(int q, string i, string u):dataItem(i), dataUnit(u), unitTotal(q), next(NULL)
{
}

string Node::getDescription( ) const
{
    return dataItem;
}

void Node::setDescription(string iSetter)
{
    dataItem = iSetter;
}

string Node::getQuantityName() const
{
    return dataUnit;
}

void Node::setQuantityName(string uSetter)
{
    dataUnit = uSetter;
}

int Node::getQuantityNumber() const
{
    return unitTotal;
}

void Node::setQuantityNumber(int tSetter)
{
    unitTotal = tSetter;
}

Node* Node::getNext() const
{
    return next;
}

void Node::setNext(Node* nSetter)
{
    next = nSetter;
}

驱动程序.cpp

int main( )
{
    //===============================================
    // PART ONE
    //===============================================
    cout << "\nPart I: push_front and pop_front\n";
    cout << "\n----------------------------------\n";
    List groceries;

    // test push_back function
    groceries.push_front(new Node(1, "gallon", "milk") );
    groceries.push_front(new Node(2, "loaves", "bread") );
    groceries.push_front(new Node(1, "dozen", "eggs" ) );
    groceries.push_front(new Node(1,  "package", "bacon") );

    cout << "\nThe original nodes in the List:\n";
    printList(groceries);
    cout << "\n----------------------------------\n";

    // test push_front function
    cout << "\nAdding to the front of the List:\n";
    cout << "\n----------------------------------\n";
    groceries.push_front(new Node(2, "lbs", "hamburger") );
    groceries.push_front(new Node(1, "dozen", "hamburger buns") );

    printList(groceries);
    cout << "\n----------------------------------\n";

    // test pop-front
    cout << "\nRemoving the first node from the list.\n";
    cout << "\n----------------------------------\n";
    Node* item = groceries.pop_front( );
    cout << "\nPopped " << item->getDescription( ) << " from the list.\n\n";
    printList(groceries);
    if (item != NULL)
        delete item;

    // ===============================================
    // PART TWO: Uncomment this block to test part two
    // ===============================================

    cout << "\n----------------------------------\n";
    cout << "\nPart Two: Push_back and pop_back";

    // test push_back
    groceries.push_back(new Node(2, "cans", "orange juice") );
    groceries.push_back(new Node(1, "lb", "swiss cheese") );

    cout << "\nAdding two nodes at the end\n";
    cout << "\n----------------------------------\n";
    printList(groceries);

    // test pop-back
    cout << "\n----------------------------------\n";
    cout << "\nRemove last node from the list\n";
    cout << "\n----------------------------------\n";
    item = groceries.pop_back( );
    cout << "\nPopped " << item->getDescription( ) << " from the list.\n\n";

    printList(groceries);
    if (item != NULL)
        delete item;
    // ============================================
    // end of part two
    // ============================================

    // ================================================
    // PART THREE: uncomment this block to test part three
    // ================================================
    /*
    // create a second list to test assignment
    cout << "\n\n--------------extra credit------------------\n";
    cout << "\n\n overloaded assignment operator\n";
    cout << "The hardware list ...\n";
    cout << "\n-------------------------------------------\n";
    List hardware;
    hardware.push_back(new Node(2, "lbs", "nails") );
    hardware.push_back( new Node(3, "gals", "white paint") );
    hardware.push_back(new Node(1, "piece", "plywood") );
    printList(hardware);
    hardware = groceries;
    cout << "\n-------------------------------------------\n";
    cout << "\nafter assignment";
    cout << "\n-------------------------------------------\n";
    printList(hardware);

    cout << "\n-------------------------------------------\n";
    cout << "\nTest the copy constructor\n";
    cout << "\n-------------------------------------------\n";
    printFirstNode(hardware);

    // ==============================================
    // end of part 3
    // ==============================================
    */
    cout << "\n-------------------------------------------\n";
    cout << "\nEnd of Test";
    cout << "\n-------------------------------------------\n";
    system("PAUSE");
    return 0;
}
4

3 回答 3

1

看起来 pop back 不会从列表中删除最后一个节点,而是返回它。然后该节点被删除,并在列表的析构函数中尝试第二次删除它。

于 2013-08-11T07:41:28.653 回答
0

push_back() 方法可能是你的罪魁祸首,再加上未能将 Node:next 初始化为零。如果仅使用 push_back 将一个节点添加到列表中,则该节点的下一个成员的值将是未知的,并且在析构函数中尝试删除引用随机内存位置的第二个节点将导致访问错误。要么确保节点值已初始化,要么确保 node.next 在 push_back() 中显式设置(如果它是添加到列表中的第一个节点)。

关于 pop_back() 和 pop_front() 的注意事项。在空列表上调用 pop_back() 仍然会减少 nodeListTotal。在空列表上调用 pop_front() 实际上会导致尝试访问地址 0 的访问冲突。

于 2013-08-11T07:14:00.200 回答
0

deletion在析构函数中清理时,节点的下面会导致问题。

if (item != NULL)
    delete item;

当你这样做时,pop_back你正在删除那个(最后一个)节点main(),但是在那之前的节点会发生什么?它指向你删除的那个并且没有设置为NULL.

因此,在析构函数中,当您开始删除节点时,您正在检查节点的NULL值。一切正常,但现在最后一个next没有设置为NULL,而是仍然指向您刚刚删除的那个。因此,尝试释放已经释放的节点。

然后你的代码崩溃了。

每当您释放后续节点时,将前一个节点设置为nextNULL

于 2013-08-11T09:01:23.603 回答