簡體   English   中英

C ++隊列模板

[英]c++ queue template

好吧,請原諒我凌亂的代碼。 下面是我的隊列類。

#include <iostream>
using namespace std; 
#ifndef QUEUE
#define QUEUE

/*----------------------------------------------------------------------------
Student Class

# Methods #
Student()               // default constructor
Student(string, int)    // constructor
display()               // out puts a student

# Data Members #
Name                    // string name
Id                      // int id
----------------------------------------------------------------------------*/
class Student { 
public: 
    Student() { } 
    Student(string iname, int iid) { 
        name = iname; 
        id = iid; 
    } 
    void display(ostream &out) const { 
        out << "Student Name: " << name << "\tStudent Id: " << id
            << "\tAddress: " << this << endl;  
    }  

private: 
    string name; 
    int id; 
}; 


// define a typedef of a pointer to a student. 
typedef Student * StudentPointer;

template <typename T> 

class Queue
{
public:
    /*------------------------------------------------------------------------
    Queue Default Constructor

    Preconditions: none
    Postconditions: assigns default values for front and back to 0

    description: constructs a default empty Queue. 
    ------------------------------------------------------------------------*/
    Queue() : myFront(0), myBack(0) {}


    /*------------------------------------------------------------------------
    Copy Constructor

    Preconditions: requres a reference to a value for which you are copying
    Postconditions: assigns a copy to the parent Queue. 

    description: Copys a queue and assigns it to the parent Queue. 
    ------------------------------------------------------------------------*/
    Queue(const T & q) { 
        myFront = myBack = 0; 
        if(!q.empty()) { 
            // copy the first node
            myFront = myBack = new Node(q.front()); 
            NodePointer qPtr = q.myFront->next; 
            while(qPtr != NULL) { 
                myBack->next = new Node(qPtr->data); 
                myBack = myBack->next; 
                qPtr = qPtr->next; 
            } 
        } 

    }
    /*------------------------------------------------------------------------
    Destructor

    Preconditions: none
    Postconditions: deallocates the dynamic memory for the Queue

    description: deletes the memory stored for a Queue. 
    ------------------------------------------------------------------------*/
    ~Queue() { 
        NodePointer prev = myFront, ptr; 
        while(prev != NULL) { 
            ptr = prev->next; 
            delete prev; 
            prev = ptr; 
        } 
    } 
    /*------------------------------------------------------------------------
    Empty()

    Preconditions: none
    Postconditions: returns a boolean value. 

    description: returns true/false based on if the queue is empty or full. 
    ------------------------------------------------------------------------*/
    bool empty() const { 
        return (myFront == NULL); 
    }
    /*------------------------------------------------------------------------
    Enqueue

    Preconditions: requires a constant reference
    Postconditions: allocates memory and appends a value at the end of a queue

    description: 
    ------------------------------------------------------------------------*/
    void enqueue(const T & value) {
        NodePointer newNodePtr = new Node(value); 
        if(empty()) { 
            myFront = myBack = newNodePtr; 
            newNodePtr->next = NULL; 
        } else { 
            myBack->next = newNodePtr; 
            myBack = newNodePtr; 
            newNodePtr->next = NULL; 
        } 
    }
    /*------------------------------------------------------------------------
    Display

    Preconditions: requires a reference of type ostream
    Postconditions: returns the ostream value (for chaining)

    description: outputs the contents of a queue. 
    ------------------------------------------------------------------------*/
    void display(ostream & out) const {
        NodePointer ptr; 
        ptr = myFront; 

        while(ptr != NULL) { 
            out << ptr->data << " "; 
            ptr = ptr->next; 
        } 
        out << endl; 
    }
    /*------------------------------------------------------------------------
    Front

    Preconditions: none
    Postconditions: returns a value of type T

    description: returns the first value in the parent Queue. 
    ------------------------------------------------------------------------*/
    T front() const {
       if ( !empty() ) 
          return (myFront->data);
       else
       {
          cerr << "*** Queue is empty -- returning garbage value ***\n";
          T * temp = new(T); 
          T garbage = * temp;
          delete temp; 
          return garbage;
       }
    }
    /*------------------------------------------------------------------------
    Dequeue

    Preconditions: none
    Postconditions: removes the first value in a queue
    ------------------------------------------------------------------------*/
    void dequeue() {
        if ( !empty() ) { 
            NodePointer ptr = myFront; 
            myFront = myFront->next; 
            delete ptr; 
            if(myFront == NULL) 
                myBack = NULL; 

        } else {
            cerr << "*** Queue is empty -- "
              "can't remove a value ***\n";
            exit(1);
        }
    }
    /*------------------------------------------------------------------------
    pverloaded = operator

    Preconditions: requires a constant reference
    Postconditions: returns a const type T

    description: this allows assigning of queues to queues
    ------------------------------------------------------------------------*/
    Queue<T> & operator=(const T &q) { 
    // make sure we arent reassigning ourself
    // e.g. thisQueue = thisQueue. 
        if(this != &q) { 
            this->~Queue(); 
            if(q.empty()) { 
                myFront = myBack = NULL; 
            } else { 
                myFront = myBack = new Node(q.front()); 
                NodePointer qPtr = q.myFront->next; 
                while(qPtr != NULL) { 
                    myBack->next = new Node(qPtr->data); 
                    myBack = myBack->next; 
                    qPtr = qPtr->next; 
                } 
            } 
        } 
        return *this; 
    }

private:
    class Node { 
    public: 
        T data; 
        Node * next; 
        Node(T value, Node * first = 0) : data(value),
                                          next(first) {}

    };  
    typedef Node * NodePointer; 

    NodePointer myFront,
               myBack,
               queueSize; 


}; 

/*------------------------------------------------------------------------
join

Preconditions: requires 2 queue values
Postconditions: appends queue2 to the end of queue1

description: this function joins 2 queues into 1. 
------------------------------------------------------------------------*/

template <typename T>
Queue<T> join(Queue<T> q1, Queue<T> q2) {
    Queue<T> q1Copy(q1), q2Copy(q2); 
    Queue<T> jQueue; 


    while(!q1Copy.empty()) { 
        jQueue.enqueue(q1Copy.front()); 
        q1Copy.dequeue(); 
    } 

    while(!q2Copy.empty()) { 
        jQueue.enqueue(q2Copy.front()); 
        q2Copy.dequeue(); 
    } 
    cout << jQueue << endl; 
    return jQueue;   

} 
/*----------------------------------------------------------------------------
Overloaded << operator 

Preconditions: requires a constant reference and a Queue of type T
Postconditions: returns the ostream (for chaining)

description: this function is overloaded for outputing a queue with <<
----------------------------------------------------------------------------*/
template <typename T>
ostream & operator<<(ostream &out, Queue<T> &s) { 
    s.display(out);  
    return out; 
} 

/*----------------------------------------------------------------------------
Overloaded << operator

Preconditions: requires a constant reference and a reference of type Student
Postconditions: none

description: this function is overloaded for outputing an object of type
             Student. 
----------------------------------------------------------------------------*/
ostream & operator<<(ostream &out, Student &s) { 
    s.display(out); 
}

/*----------------------------------------------------------------------------
Overloaded << operator

Preconditions: requires a constant reference and a reference of a pointer to
               a Student object. 
Postconditions: none

description: this function is overloaded for outputing pointers to Students
----------------------------------------------------------------------------*/
ostream & operator<<(ostream &out, StudentPointer &s) { 
    s->display(out); 
}
#endif

現在我遇到了一些問題。 首先,當我將0添加到隊列中,然后像這樣輸出隊列時。

Queue<double> qdub; 
qdub.enqueue(0); 
cout << qdub << endl; 

那行得通,它將輸出0。但是,例如,如果我以任何方式修改該隊列,例如將其分配給其他隊列。

Queue<double> qdub1; 
Queue<double> qdub2; 
qdub1.enqueue(0; 
qdub2 = qdub1; 
cout << qdub2 << endl; 

它將給我0的怪異值,如:7.86914e-316。

幫助將不勝感激!

您尚未定義副本構造函數或賦值運算符。 您擁有的是隊列類型的實例,而不是另一個隊列。 對於自己分配和復制隊列,編譯器仍將使用自動生成的做錯事情的隊列。

(這可能無法解釋該特定代碼段的輸出。)

另一件事是完全錯誤的(即使再次,該代碼段也永遠不會調用此函數,否則到處都會出現編譯器錯誤):

Queue<T> & operator=(const T &q) {
// make sure we arent reassigning ourself
// e.g. thisQueue = thisQueue.
    if(this != &q) {
        this->~Queue();

那樣明確地調用析構函數,然后再繼續使用該實例是不允許的。 顯式析構函數調用僅與構造具有新放置的對象並存。

通常根據復制構造函數和swap方法(在兩個實例之間交換內部表示)實現operator=

void swap(Queue<T>& rhv)
{
   std::swap(myFront, rhv.myFront);
   std::swap(myBack, rhv.myBack);
   std::swap(queueSize, rhv.queueSize);
}

Queue<T>& operator=(const Queue<T>& rhv)
{
   Queue<T> copy(rhv);
   this->swap(copy);
} //the destructor of copy releases the previous contents of *this

我在那里沒有看到賦值運算符,這意味着您將獲得編譯器生成的默認值,該值將進行淺表復制。 您可能需要提供自己的副本來進行深層復制。 您的評論中所說的拷貝ctor也不是拷貝ctor。 復制ctor 始終對要復制的對象采用const引用,因此簽名為: Queue(Queue const &original);

您需要適當的賦值運算符。 您的示例可能不會編譯您提供類的方式。

即使我錯了,您代碼中的主要錯誤也是您的operator=調用了它自己的析構函數。 這是非常錯誤的。 析構函數隨后也會調用“自然地”。 這意味着您的對象將被刪除兩次。 (因為您沒有在析構函數中為Queue.myFront分配NULL。)

不要手動調用析構函數。

對於基本練習,我建議您在qdub2 = qdub1行上放置一個斷點,然后逐步調試以查看代碼的實際作用。

根據通用編碼標准,您不應致電

this->~Queue()

通過該語句,對象試圖刪除自身。 嘗試將數據復制到新隊列中,如果超出范圍則將其刪除。 否則請保持原樣。

理解C ++模板的另一個示例

暫無
暫無

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

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