шаблон очереди c ++ - PullRequest
       10

шаблон очереди c ++

1 голос
/ 21 апреля 2010

Хорошо, простите мой грязный код, пожалуйста. Ниже мой класс очереди.

#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.

Помощь по этому вопросу будет высоко ценится!

Ответы [ 4 ]

6 голосов
/ 21 апреля 2010

Вы не определили конструктор копирования или оператор присваивания. Те, что у вас есть, берут экземпляр типа очереди, а не другую очередь. Для назначения и копирования самих очередей компилятор будет по-прежнему использовать автоматически сгенерированные, которые делают неправильные действия.

(Вероятно, это не объясняет вывод этого конкретного фрагмента.)

Еще одна вещь, которая совершенно неверна (хотя, опять же, фрагмент никогда не вызывает эту функцию, или вы получите ошибки компилятора повсюду):

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

Вызывать деструктор в явном виде подобным образом, а затем использовать экземпляр не разрешается. Явные вызовы деструкторов идут рука об руку с созданием объектов с размещением new.

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
1 голос
/ 21 апреля 2010

Вам нужен правильный оператор присваивания. Ваш пример, вероятно, не скомпилирует способ, которым вы предоставили свой класс.

Даже если я ошибаюсь, главная ошибка в вашем коде состоит в том, что ваш operator= вызывает свой собственный деструктор. Это ужасно неправильно. Позже деструктор также будет вызываться «естественно». Это означает, что ваши объекты будут удалены дважды. (Потому что вы не назначаете NULL для Queue.myFront в своем деструкторе.)

Не вызывать деструкторы вручную.

Для базового упражнения я рекомендую поместить точку останова в строку qdub2 = qdub1, а затем выполнить пошаговую отладку, чтобы увидеть, что на самом деле делает ваш код.

1 голос
/ 21 апреля 2010

Я не вижу там оператора присваивания, что означает, что вы получаете сгенерированный компилятором по умолчанию, который будет делать поверхностную копию. Вы, вероятно, должны предоставить свой собственный, чтобы сделать глубокую копию вместо этого. То, что ваши комментарии называют копирующим ctor, на самом деле не является копирующим ctor. Копия ctor всегда принимает константную ссылку на копируемый объект, поэтому подпись будет: Queue(Queue const &original);.

0 голосов
/ 24 ноября 2014

В соответствии с общим стандартом кодирования не следует звонить

this->~Queue()

с помощью этого оператора объект пытается удалить себя. попытайтесь скопировать данные в новую очередь, а затем удалите их, если они выходят за рамки. в противном случае оставьте все как есть.

другой пример для понимания шаблона C ++

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...