簡體   English   中英

c + +嵌套初始化模板隊列類

[英]c++ nested initialization of template queue class

嘿,我創建了這個模板化的Queue類,該類適用於所有類型,但由於某種原因而嵌套在自身中。

這是隊列類:

#ifndef QUEUE_H
#define QUEUE_H

//Queue node class.
template <class T>
class QueueNode
{
    public:
        T m_Data;
        QueueNode *m_NextNode;
        QueueNode(const T data_, QueueNode *nextValue_ = NULL)
        {
            m_Data = data_;
            m_NextNode = nextValue_;
        }
        QueueNode(QueueNode *nextValue_ = NULL)
        {
            m_NextNode = nextValue_;
        }
};

//Queue class.
template <class T>
class Queue
{
    public:
        ////////////////////////////////////////////////////////////
        // CONSTRUCTORS AND DESTRUCTORS
        ////////////////////////////////////////////////////////////
        Queue();
        ~Queue();

        ////////////////////////////////////////////////////////////
        // Error Codes
        ////////////////////////////////////////////////////////////
        enum ERC_QUEUE
        {
            ERC_NO_ERROR,
            ERC_QUEUE_EMPTY
        };

        ////////////////////////////////////////////////////////////
        // METHODS
        ////////////////////////////////////////////////////////////
        //Check if queue is empty.
        bool IsEmpty();

        //Check if queue is empty.
        int GetQueueSize();

        //Clear the queue.
        void Clear();

        //Dequeue X nodes and delete them.
        //If there the requested number of nodes to delete exceeds the number of nodes in the actual list,
        //the function will return an empty list.
        void Queue<T>::FlushNodes(unsigned short numNodes);

        //Add an item to the end of the queue.
        void Enqueue(T data_);

        //Get an item from the front of the queue.
        ERC_QUEUE Dequeue(T &data_);

        //Get an item from the front of the queue without removing it.
        ERC_QUEUE Peek(T &data_);

    private:
        QueueNode<T> *m_Head;
        QueueNode<T> *m_Tail;
        int m_Size;
};


//Template implementation

template <class T>
Queue<T>::Queue()
    : m_Size(0)
{
    //Create empty queue with front and rear pointing to NULL.
    m_Head = m_Tail = NULL;
}

template <class T>
Queue<T>::~Queue()
{
    Clear();
}

template <class T>
bool Queue<T>::IsEmpty()
{
    //If front is NULL then the queue is empty.
    return m_Head == NULL;
}

template <class T>
int Queue<T>::GetQueueSize()
{
    return m_Size;
}

template <class T>
void Queue<T>::Clear()
{
    QueueNode<T> *tmp;

    //Go through each node until the end of the queue.
    while (m_Head != NULL)
    {
        //Point tmp to next node.
        tmp = m_Head->m_NextNode;

        //Delete current node.
        delete m_Head;

        //Point front to next node.
        m_Head = tmp;
    }

    m_Size = 0;
}

template <class T>
void Queue<T>::FlushNodes(unsigned short numNodes)
{
    QueueNode<T> *tmp;

    //Go through each node until the end of the queue or the number of requested
    //nodes to be removed have been removed.
    while (m_Head != NULL && numNodes != 0)
    {
        numNodes--;
        m_Size--;

        //Point tmp to next node.
        tmp = m_Head->m_NextNode;

        //Delete current node.
        delete m_Head;

        //Point front to next node.
        m_Head = tmp;
    }
}

template <class T>
void Queue<T>::Enqueue(T data_)
{
    //Create new node.
    QueueNode<T> *node = new QueueNode<T>(data_);
    m_Size++;

    //If queue is empty then point both front and rear to the new node.
    if (IsEmpty())
    {
        m_Head = m_Tail = node;
        return;
    }

    //Add node to the end of the queue and repoint rear to the new node.
    m_Tail->m_NextNode = node;
    m_Tail = node;
}

template <class T>
typename Queue<T>::ERC_QUEUE Queue<T>::Dequeue(T &data_)
{
    //If queue is empty return NULL.
    if (IsEmpty())
    {
        return Queue<T>::ERC_QUEUE_EMPTY;
    }

    //Save value from top node.
    data_ = m_Head->m_Data;

    //Point tmp to front.
    QueueNode<T> *tmp = m_Head;

    //Repoint front to the second node in the queue.
    m_Head = m_Head->m_NextNode;

    //Remove first node.
    delete tmp;

    //Update queue size.
    m_Size--;

    return Queue<T>::ERC_NO_ERROR;
}

template <class T>
typename Queue<T>::ERC_QUEUE Queue<T>::Peek(T &data_)
{
    //If queue is empty return NULL.
    if (IsEmpty())
    {
        return Queue<T>::ERC_QUEUE_EMPTY;
    }

    data_ = m_Head->m_Data;

    return Queue<T>::ERC_NO_ERROR;
}

#endif //QUEUE_H

這是我想做的:

Queue<int>          tst;
Queue<Queue<int>>   tst2;

tst.Enqueue(1);
tst.Enqueue(2);
tst.Enqueue(3);

tst2.Enqueue(tst);

一切都可以編譯,但是程序在運行時崩潰。 這是怎么回事!?

一個明顯的錯誤是您使用的T類型無法安全復制。

你做這個:

void Enqueue(T data_);

但是,如果類型TQueue<int> ,您認為data_發生了什么? 復制完成,並且您的Queue模板類沒有正確的復制語義。 它缺少用戶定義的副本構造函數和賦值運算符。

崩潰發生在tst2的析構函數中,因為這是一個Queue<Queue<int>> ,並且您已經在析構函數調用之前通過調用tst2.Enqueue(tst);tst2.Enqueue(tst);了存儲方式tst2.Enqueue(tst); 打電話給您,您就死了(或將要死)。

您在多個地方都有相同的錯誤,也就是說,您正在復制不可安全復制的對象。

例:

//Save value from top node.
data_ = m_Head->m_Data;

如果data_是一個Queue<int> ,還是那句話,你的水就死定了,因為分配Queue<int>一個Queue<int>是一個沒有去。

因此,解決此問題的方法是讓Queue類實現3規則,以確保副本正常工作。 您需要實現以下功能:

Queue(const Queue& rhs);
Queue& operator=(const Queue& rhs);

另外,使用以下情況進行測試:

int main()
{
    Queue<int> q1;
    q1.Enqueue(10);
    Queue<int> q2;
    q2 = q1;
    Queue<int> q3 = q2;
}

這樣的程序在main退出時不應該崩潰,顯示內存泄漏的跡象等。 如果是這樣,則說明您沒有正確實現復制。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM