简体   繁体   English

C ++调试断言失败

[英]C++ Debug Assertion Failed

I've written my own list class for practice, here it is: 我已经编写了自己的列表类进行练习,这里是:

#pragma once

#include <iostream>

using namespace std;

// A linked node structure.
template <typename T>
struct LinkedNode
{
    T data;
    LinkedNode<T>* next;
    LinkedNode<T>* prev;
};

// Class linked list.
template <typename T>
class LinkedList
{
public:

    // Constructor
    LinkedList()
    {
        mFirst = 0;
        mLast = 0;
    }

    LinkedList(const LinkedList& rhs)
    {
        mFirst = 0;
        mLast = 0;

        // Get a pointer to the first node of rhs.
        LinkedNode<T>* current = rhs.mFirst;

        // While not at the end of the rhs linked list.
        while( current != 0 )
        {
            insertLast( current->data );
            current = current->next;
        }
    }

    // Destructor
    ~LinkedList()
    {
        destroy();
    }

    // Overload
    LinkedList& operator=(const LinkedList& rhs)
    {
        // Check for self assignment
        if ( this == &rhs )
            return *this;

        // Get a pointer to the first node of rhs.
        LinkedNode<T>* current = rhs.mFirst;

        // While not at the end of the rhs linked list.
        while( current != 0 )
        {
            insertLast( current->data );
            current = current->next;
        }

        // Chain assignments a = b = c = d
        return *this;
    }

    // Check if list is empty.
    bool isEmpty()
    {
        if( mFirst == 0 && mLast == 0 )
            return true;
        else
            return false;
    }

    // Return first and last nodes.
    LinkedNode<T>* getFirst() { return mFirst; };
    LinkedNode<T>* getLast()  { return mLast;  };

    void insertFirst(T tData);
    void insertLast(T tData);
    bool insertAfter(T tKey, T tData);
    void removeFirst();
    void removeLast();
    void remove(T removalCandidate);
    void destroy();

private:

    LinkedNode<T>* mFirst;
    LinkedNode<T>* mLast;
};

template <typename T>
bool LinkedList<T>::insertAfter(T tKey, T tData)
{
    if( isEmpty() ) return false;

    // Get a pointer to the front of the list
    LinkedNode<T>* current = mFirst;

    // Loop until we find the tKey (the value of the node to insert after)
    while( current->data != tKey )
    {
        // Hop to the next node.
        current = current->next;

        // Test if we reached the end, if we did we didn't find the node to insert after (tKey)
        if( current == 0 )
            return false;
    }

    // Allocate memory for the new node to insert.
    LinkedNode<T>* newNode = new LinkedNode<T>();
    newNode->data = tData;

    // Special case: Are we inserting after the last node?
    if( current == mLast )
    {
        newNode->next = 0;
        mLast = newNode;
    }
    // No, else link in new node after the current node.
    else
    {
        newNode->next = current->next;
        newNode->next->prev = newNode;
    }

    newNode->prev = current;
    current->next = newNode;

    return true;
}

template <typename T>
void LinkedList<T>::insertFirst(T tData)
{
    LinkedNode<T>* newNode = new LinkedNode<T>();
    newNode->data = tData;

    // If the list is empty, then this is the first and last node and doesn't have a previous pointer.
    if( isEmpty() )
        mLast = newNode;
    // If the list is not empty, the new node becomes the previous node of the current first node.
    else
        mFirst->prev = newNode;

    // The new node's next pointer is the old first pointer. May be null if this is the first node being added to the list.
    newNode->next = mFirst;

    //The new node becomes the first node.
    mFirst = newNode;   
}

template <typename T>
void LinkedList<T>::insertLast(T tData)
{
    LinkedNode<T>* newNode = new LinkedNode<T>();
    newNode->data = tData;

    if( isEmpty() )
        mFirst = newNode;
    else
        mLast->next = newNode;

    newNode->prev = mLast;

    mLast = newNode;
}

template <typename T>
void LinkedList<T>::removeFirst()
{

    if( !isEmpty() )
    {
        LinkedNode<T>* current = mFirst;

        if( mFirst == mLast )
        {
            mFirst->next = 0;
            mLast->prev = 0;
        }
        else
        {
            mFirst = current->next;
            mFirst->prev = 0;
        }

        delete current;
        current = 0;
    }   
}

template <typename T>
void LinkedList<T>::removeLast()
{
    if( !isEmpty() )
    {
        LinkedNode<T>* current = mLast;

        if( mFirst == mLast )
        {
            mFirst = 0;
            mLast = 0;
        }
        else
        {
            mLast = current->prev;
            mLast->next = 0;
        }

        delete current;
        current = 0;
    }
}

template <typename T>
void LinkedList<T>::remove(T removalCandidate)
{
    LinkedNode<T>* current = mFirst;

    if( isEmpty() )
    {
        cout << "List is empty!" << endl;
    }
    else
    {
        while( current->data != removalCandidate )
        {
            if( current->data == removalCandidate )
            {
                break;
            }
            current = current->next;
        }
    }

    if( current == mFirst )
        removeFirst();
    else if ( current == mLast )
        removeLast();
    else
    {
        // Create two linked nodes to access the next and prev nodes.
        LinkedNode<T>* left  = current->prev;
        LinkedNode<T>* right = current->next;

        left->next = right;
        right->prev = left;
    }

    delete current;
    current = 0;
}

template <typename T>
void LinkedList<T>::destroy()
{
    // Is there at least one node in the list?
    if( mFirst != 0 )
    {
        // Get a pointer to the first node.
        LinkedNode<T>* current = mFirst;

        // Loop until we reach the end of list.
        while( current != 0 )
        {
            // Save the current node.
            LinkedNode<T>* oldNode = current;

            // Move to next node.
            current = current->next;

            // Delete saved node.
            delete oldNode;
            oldNode = 0;
        }
    }

    mFirst = 0;
}

Then I have also written a stack and queue class, and I test them both to see whether a string is a palindrome. 然后,我还编写了一个堆栈和队列类,并对它们都进行了测试,以查看字符串是否是回文。 That all works. 一切正常。 However when it runs the destroy method in the list class, it throws a: block type is valid(pHead->nBlockUse) error on the 但是,当它在list类中运行destroy方法时,它将在以下位置抛出一个:块类型有效(pHead-> nBlockUse)错误。

delete oldNode;

line. 线。

Queue code: 队列代码:

#pragma once

#include <iostream>
#include "LinkedList.h"

#include <cassert>

template <typename T>
class Queue
{
public:
    Queue(){};

    ~Queue()
    {
        mList.destroy();
    }

    T& getFirst()
    {
        assert( !isEmpty() );
        return mList.getFirst()->data;
    }

    bool isEmpty( void )
    {
        return mList.isEmpty();
    }

    void push( T newElement )
    {
        mList.insertLast( newElement );
    }

    void pop()
    {
        mList.removeFirst();
    }

private:
    LinkedList<T> mList;
};

Stack code: 堆栈代码:

#pragma once

#include <iostream>
#include "LinkedList.h"

#include <cassert>

template <typename T>
class Stack
{
public:
    Stack(){};

    ~Stack()
    {
        mList.destroy();    
    }

    T& getTopItem()
    {
        // Throw error if list is empty.
        assert( !isEmpty() );

        return mList.getLast()->data;
    }

    bool isEmpty( void )
    {
        return mList.isEmpty(); 
    }

    void push( T newElement )
    {
        mList.insertLast( newElement );
    }

    void pop()
    {
        mList.removeLast();
    }

private:
    LinkedList<T> mList;
};

Main code: 主要代码:

#include "Stack.h"
#include "Queue.h"
#include <iostream>
#include <string>
using namespace std;

int main()
{

    Stack<char> strStack;
    Queue<char> strQueue;

    cout << "Enter a string: ";
    string input = "";
    getline(cin, input);

    for( unsigned int i = 0; i < input.length(); ++i )
    {
        strStack.push( input[i] );
        strQueue.push( input[i] );
    }

    bool isPalindrome = true;

    // FIX PALINDROME AND ASSERTION FAIL

    for( unsigned int j = 0; j < input.length(); ++j )
    {
        if( strStack.getTopItem() != strQueue.getFirst() )
        {
            isPalindrome = false;
            break; // Exit for loop early.
        }

        // Get rid of next element out.
        strStack.pop();
        strQueue.pop();
    }

    cout << input << " is palindrome: " << isPalindrome << endl;
}

I'm not sure why, any help would be appreciated. 我不确定为什么,任何帮助将不胜感激。

The problem is in the removeFirst function: When you remove the last node in the list (ie mFirst == mLast is true ) you set the node link pointers to 0 , and then you delete the node. 问题出在removeFirst函数中:删除列表中的最后一个节点(即mFirst == mLasttrue )时,请将节点链接指针设置为0 ,然后删除该节点。 Now both mFirst and mLast points to a deleted node! 现在, mFirstmLast指向已删除的节点!

Instead of setting the next and prev links to 0 , you should set mFirst and mLast to 0 . 不要将nextprev链接设置为0 ,而应将mFirstmLast设置为0 Just like you already do in removeLast . 就像您已经在removeLast所做的一样。

Because you are not setting mFirst to NULL (0) right before the destroy() method returns. 因为您没有在destroy()方法返回之前将mFirst设置为NULL(0)。 If you call destroy() more than once, you'll hit this kind of crt assertion as a result of attempting to delete a pointer twice. 如果您多次调用destroy(),则由于尝试两次删除指针,您将遇到这种crt断言。 The queue class calls mList.destroy in its destructor, but the destructor of mList will call destroy again. 队列类在其析构函数中调用mList.destroy,但是mList的析构函数将再次调用destroy。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM