2010-04-20 2 views
1

Très bien, pardonnez mon code désordonné s'il vous plaît. Voici ma classe de file d'attente.C++ file d'attente modèle

#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 

Maintenant j'ai quelques problèmes avec cela. D'une part, quand j'ajoute 0 à une file d'attente puis je sortie la file d'attente comme si ..

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

qui fonctionne, ce sera la sortie 0. Mais par exemple, si je peux modifier cette file d'attente de quelque façon .. comme .. l'affecter à une autre file d'attente ..

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

il me donnera des valeurs étranges pour 0 comme .. 7.86914e-316.

Une aide à ce sujet serait grandement appréciée!

+1

7,86914 x 10^-316 au lieu de zéro est arrondi probablement erreur. Envisagez de définir le flux de sortie sur des valeurs arrondies pour vous. – WhirlWind

+0

Que se passe-t-il si vous mettez en file d'attente 1.0? – Robb

+0

0 peut être exprimé exactement en format binaire flottant, donc il n'y a pas d'arrondi. – shoosh

Répondre

6

Vous n'avez pas défini de constructeur de copie ou d'opérateur d'affectation. Ceux que vous avez prennent une instance du type en file d'attente, pas une autre file d'attente. Pour l'assignation et la copie des files d'attente elles-mêmes, le compilateur utilisera toujours les files générées automatiquement qui font la mauvaise chose.

(Cela n'explique probablement pas la sortie de cet extrait particulier.)

Une autre chose qui est complètement faux (même si, encore une fois, l'extrait invoque jamais cette fonction ou vous obtiendrez des erreurs du compilateur partout l'endroit):

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

Appeler le destructeur explicitement comme ça, et ensuite continuer à utiliser l'instance n'est pas autorisé. Les appels destructeurs explicites ne vont que de pair avec la construction d'objets avec un placement nouveau.

operator= est normalement mis en œuvre en termes de constructeur de copie et une méthode d'échange (qui permute la représentation interne entre deux instances):

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

je ne vois pas un opérateur d'affectation là-bas, ce qui signifie que vous êtes obtenir le compilateur généré par défaut, ce qui fera une copie superficielle. Vous devez probablement fournir le vôtre pour faire une copie profonde à la place. Ce que vos commentaires appellent une copie ctor n'est pas vraiment une copie ctor non plus. Une copie ctor toujours prend une référence const à l'objet en cours de copie, donc la signature serait: Queue(Queue const &original);.

1

Vous avez besoin d'un opérateur d'affectation approprié. Votre exemple ne compilera probablement pas la façon dont vous avez fourni votre classe.

Même si je me trompe, la principale erreur dans votre code est que votre operator= appelle son propre destructeur. C'est horriblement faux. Le destructeur sera appelé plus tard «naturellement». Cela signifie que vos objets seront supprimés deux fois. (Parce que vous n'attribuez pas NULL à Queue.myFront dans votre destructor.)

Don't manually call destructors.

Pour un exercice de base, je vous recommande de placer un point d'arrêt sur la ligne qdub2 = qdub1 puis étape de débogage par étape pour voir ce que fait vraiment votre code.

0

Selon la norme de codage général, vous ne devez pas appeler

this->~Queue() 

par cette déclaration un objet tente de se supprimer. essayez de copier des données dans une nouvelle file d'attente, puis supprimez-le s'il est hors de portée. sinon, gardez-le tel quel.

une autre example pour comprendre C++ modèle