简体   繁体   English

C ++队列模板

[英]c++ queue template

ALright, pardon my messy code please. 好吧,请原谅我凌乱的代码。 Below is my queue class. 下面是我的队列类。

#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

Now I'm having some issues with it. 现在我遇到了一些问题。 For one, when I add 0 to a queue and then I output the queue like so.. 首先,当我将0添加到队列中,然后像这样输出队列时。

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

That works, it will output 0. But for example, if I modify that queue in any way.. like.. assign it to a different queue.. 那行得通,它将输出0。但是,例如,如果我以任何方式修改该队列,例如将其分配给其他队列。

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

It will give me weird values for 0 like.. 7.86914e-316. 它将给我0的怪异值,如:7.86914e-316。

Help on this would be much appreciated! 帮助将不胜感激!

Your haven't defined a copy constructor or an assignment operator. 您尚未定义副本构造函数或赋值运算符。 The ones you have take an instance of the queued type, not another queue. 您拥有的是队列类型的实例,而不是另一个队列。 For assigning and copying queues themselves, the compiler will still use the automatically generated ones which do the wrong thing. 对于自己分配和复制队列,编译器仍将使用自动生成的做错事情的队列。

(This probably doesn't explain the output of that particular snippet.) (这可能无法解释该特定代码段的输出。)

Another thing that is completely wrong (even though, again, the snippet never invokes this function or you'd get compiler errors all over the place): 另一件事是完全错误的(即使再次,该代码段也永远不会调用此函数,否则到处都会出现编译器错误):

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

Calling destructor explicitly like that, and then going on to use the instance is not allowed. 那样明确地调用析构函数,然后再继续使用该实例是不允许的。 Explicit destructor calls only go hand in hand with constructing objects with placement new. 显式析构函数调用仅与构造具有新放置的对象并存。

operator= is normally implemented in terms of copy constructor and a swap method (which swaps the internal representation between two instances): 通常根据复制构造函数和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

I don't see an assignment operator there, which means you're getting the compiler generated default, which will do a shallow copy. 我在那里没有看到赋值运算符,这意味着您将获得编译器生成的默认值,该值将进行浅表复制。 You probably need to supply your own to do a deep copy instead. 您可能需要提供自己的副本来进行深层复制。 What your comments call a copy ctor isn't really a copy ctor either. 您的评论中所说的拷贝ctor也不是拷贝ctor。 A copy ctor always takes a const reference to the object being copied, so the signature would be: Queue(Queue const &original); 复制ctor 始终对要复制的对象采用const引用,因此签名为: Queue(Queue const &original); .

You need a proper assignment operator. 您需要适当的赋值运算符。 Your example would probably not compile the way you provided your class. 您的示例可能不会编译您提供类的方式。

Even if I am wrong, the main mistake in your code is that your operator= calls it's own destructor. 即使我错了,您代码中的主要错误也是您的operator=调用了它自己的析构函数。 This is horribly wrong. 这是非常错误的。 The destructor will later called 'naturally' on as well. 析构函数随后也会调用“自然地”。 This means that your objects will be deleted twice. 这意味着您的对象将被删除两次。 (Because you don't assign NULL to Queue.myFront in your destructor.) (因为您没有在析构函数中为Queue.myFront分配NULL。)

Don't manually call destructors. 不要手动调用析构函数。

For a basic exercise, I recommend that you place a breakpoint on the line qdub2 = qdub1 and then debug step by step to see what your code really does. 对于基本练习,我建议您在qdub2 = qdub1行上放置一个断点,然后逐步调试以查看代码的实际作用。

According to general coding standard you should not call 根据通用编码标准,您不应致电

this->~Queue()

through this statement a object is trying to delete itself. 通过该语句,对象试图删除自身。 try to copy data into new queue and then delete it if it goes out of scope. 尝试将数据复制到新队列中,如果超出范围则将其删除。 otherwise keep it as it is. 否则请保持原样。

another example for understanding C++ template 理解C ++模板的另一个示例

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

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