繁体   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