Hello Everyone,
I am working on an assignment using a Queue data structure. We basically create an array and manually define the member functions (first(), enqueue(), dequeue(), etc...) so that it acts like a queue (FIFO arrangement).
I created my header file (ArrayQueue.h) which is a template class that creates a new array of Objects with a capacity of 1000. I then defined my functions. In the first(), enqueue(), and dequeue() I created if statements that would throw exceptions if the queue was empty or full. The exceptions are derived from an exception class I created (exceptions.h).
There is also a marathon.h file that creates racer objects and assigns them bib numbers, ages (randomly), and finish times (sequentially) and stores them in a vector of Racer objects. This file was created by the teacher. Our assignment was to sort the racer objects from the vector into 5 different age categories (5 seperate queues). I have this working, but theres something wrong with my exceptions and my copy constructor or operator= function.
All of the code compiles properly, but when I try to test the exception functions by purposely throwing an exception the program crashes!
As far as the copy constructor goes, it sucessfully copies from one queue to another, but then crashes during the output. If anyone can educate me as to why this is failing i would be eternally grateful!
here is the code. I have placed the areas where i try to test my exception and copy/operator= functions in asterisks (**********************)
My exceptions are defined in Exceptions.h and thrown in ArrayQueue.h. in the first(), enqueue(), and dequeue() functions.
Thanks so much for your help.
Exceptions.h
#ifndef EXCEPTIONS_H
#define EXCEPTIONS_H
#include <exception>
#include <string>
using std::runtime_error;
using std::string;
class QueueFullException : public runtime_error{
public:
QueueFullException(const string msg = "The Queue is Full")
:runtime_error( msg ) { }
};
class QueueEmptyException : public runtime_error{
public:
QueueEmptyException(const string msg = "The Queue is Empty")
:runtime_error( msg ) { }
};
#endif
ArrayQueue.h
#ifndef ARRAYQUEUE_H
#define ARRAYQUEUE_H
#include "Exceptions.h"
const int CAPACITY = 1000;
template <typename Object>
class ArrayQueue{
private:
int cap;
int front; // queue is empty when front == rear
int rear;
Object *pObjectArray;
public:
ArrayQueue( int sz = CAPACITY )
{
cap = sz;
pObjectArray = new Object[cap];
front = 0;
rear = 0;
}
~ArrayQueue()
{
delete [] pObjectArray;
}
ArrayQueue( const ArrayQueue& rhs ) {
rear = rhs.rear;
cap = rhs.cap;
pObjectArray = new Object[cap]; // allocate memory
for(int i = 0; i <= rear; ++i)
{
pObjectArray[i] = rhs.pObjectArray[i];
}
}
int size(){return (cap - front + rear) % cap;}
bool isEmpty() {return front == rear;}
void enqueue( const Object& element )
{
if ( size() == (cap - 1) ) { throw QueueFullException(); }
pObjectArray[rear] = element;
rear = (rear+1) % cap;
}
Object dequeue()
{
if ( isEmpty()) {throw QueueEmptyException(); }
Object temp = pObjectArray[front];
front = (front+1) % cap;
return temp;
}
Object& first()
{
if( isEmpty()) { throw QueueEmptyException(); }
return pObjectArray[front];
}
ArrayQueue& operator=(const Object &rhs) {
if( this != &rhs )
{
delete [] pObjectArray; // free old memory
rear = rhs.rear;
cap = rhs.cap;
pObjectArray = new Object[cap]; // allocate new memory
for( int i=0; i < rear; i++ )
{
pObjectArray[i] = rhs.pObjectArray[i]; // copy values
}
}
return *this;
}
Marathon.h
* EXAMPLE OF USE:
* const int RACERS = 100;//The number of people in the race
* RaceTimer myRace(RACERS);//Creates a race with all the racers and results
*
* //Get the vector of racers
* vector<Racer> results = myRace.getResults();
*
* //Print the results in a table
* cout << "Bib\tMinutes\tAge" << endl;
* for( int i=0; i<results.size(); ++i ) {
* Racer& temp = results.at(i);
* cout << temp.getBibNumber() << "\t"
* << temp.getFinishTime() << "\t"
* << temp.getAge() << endl;
* }
*/
#ifndef MARATHON_H
#define MARATHON_H
#include <ctime>
#include <vector>
#include <algorithm>
using std::vector;
using std::sort;
const int MIN_AGE = 18;
const int MAX_AGE = 69;
const int MAX_RACERS = 100;
const int MAX_BIB = 1000;
const int SLOWEST_TIME = 300;//Time in minutes
// Represents a person who is racing in the marathon
class Racer {
private:
int bibNumber;
int finishTime;
int age;
public:
Racer():bibNumber(0),finishTime(0),age(20) { }
int getBibNumber() const {return bibNumber;}
int getFinishTime() const {return finishTime;}
int getAge() const {return age;}
void setBibNumber(int bib=0){ bibNumber = ((bib>0) ? bib : -bib); }
void setFinishTime(int time=0){
finishTime = ((time<SLOWEST_TIME && time>0) ? time : SLOWEST_TIME);
}
void setAge(int yr){ (yr<=MAX_AGE && yr>=MIN_AGE) ? age=yr : age=MIN_AGE; }
};//End of Racer class
// Simulates a marathon timing device that returns data on each runner
// as they cross the finish line. The data is returned all at once as a
// reference to a vector of Racer objects by the getResults() method.
class RaceTimer {
public:
//Constructor
RaceTimer(int num=100):numberRacers(num){
start();
}
//Returns the racer objects in the order they crossed the finish line
const vector<Racer>& getResults() const {
return racers;
}
//Function to compare 2 racers, used by sort()
static bool comp(const Racer& i, const Racer& j) {
return (i.getFinishTime() < j.getFinishTime());
}
private:
int numberRacers;//The number of people in the marathon
vector<Racer> racers;//Vector of Racer objects
void start();//Utility method to generate the racers and all their data
};//End of RaceTimer class
//Utility method for RaceTimer to generate the racers and all their data
void RaceTimer::start(){
//Seed the random number generator
srand((unsigned)time(0));
//For each runner
// Make a new racer
// Set the bib number
// Set the age
// Set the finish time
// Add to the vector
for(int i=0; i<numberRacers; ++i) {
//Make a new racer
Racer tempRacer;
//Get a consecutive bib number for this runner
int bib = MAX_BIB + i;
tempRacer.setBibNumber(bib);
//Get a random age for this runner
int age = MIN_AGE + rand() % (MAX_AGE-MIN_AGE);
tempRacer.setAge(age);
//Get the fastest possible time for the age group of this runner
int fastestTime = 0;
int ageGroup = age/10;
switch(ageGroup){
case 1://18-19 age group
case 2://20-29 age group
case 3://30-39 age group
fastestTime = 140;
break;
case 4://40-49 age group
fastestTime = 150;
break;
case 5://50-59 age group
fastestTime = 165;
break;
case 6://60-69 age group
fastestTime = 185;
break;
default://anyone else
fastestTime = 185;
break;
}
//Calculate a random finish time for this runner
int time = fastestTime + rand() % (SLOWEST_TIME - fastestTime);
tempRacer.setFinishTime(time);
//Append the racer to the end of the vector
racers.push_back(tempRacer);
}
//Sort the results according to the finishing times to
//simulate the order of the runners crossing the finish line
sort(racers.begin(),racers.end(),&comp);
}//End of start()
#endif
main.cpp
#include <iostream>
#include "marathon.h"
#include "ArrayQueue.h"
using namespace std;
int main(){
const int RACERS = 100;//The number of people in the race
RaceTimer myRace(RACERS);//Creates a race with all the racers and results
//Get the vector of racers
vector<Racer> results = myRace.getResults();
ArrayQueue<Racer> cat1; //Queue for age groups 18-29
ArrayQueue<Racer> cat2; //Queue for age groups 30-39
ArrayQueue<Racer> cat3; //Queue for age groups 40-49
ArrayQueue<Racer> cat4; //Queue for age groups 50-59
ArrayQueue<Racer> cat5; //Queue for age groups 60-69
//*****************************************************************************************
// This is where I attempt to make the program throw a QueueEmptyException.
// unfortunately, it just crashes the program!!!
// Racer test = cat1.first(); //making program throw an exception.
//*****************************************************************************************
//looping through vector to create age category queues.
for( int i=0; i < results.size(); ++i ) {
Racer& temp = results.at(i);
//cout << i << "\t" << temp.getBibNumber() << "\t" << temp.getFinishTime() << "\t" << temp.getAge() << endl;
int racerAge = temp.getAge();
if (racerAge >= 18 && racerAge <= 29) { cat1.enqueue(temp); }
else if (racerAge >= 30 && racerAge <= 39) { cat2.enqueue(temp); }
else if (racerAge >= 40 && racerAge <= 49) { cat3.enqueue(temp); }
else if (racerAge >= 50 && racerAge <= 59) { cat4.enqueue(temp); }
else if(racerAge >= 60 && racerAge <= 69) { cat5.enqueue(temp); }
//****************************************************************************************
//Testing copy constructor/operator= constructor. Queues copy but program crashes after output.
//cat2 = cat1;
//cat3 = cat1;
//******************************************************************************************
}
// load the racer with the fastest time into a gc (grand champion) racer object.
Racer gc = results.at(0);
// place the winner from each age category into a Racer object
Racer cat1Winner = cat1.first();
Racer cat2Winner = cat2.first();
Racer cat3Winner = cat3.first();
Racer cat4Winner = cat4.first();
Racer cat5Winner = cat5.first();
// determine grand champion by comparing the winners from each age category.
// This is how i originally found the grand champion, but an easier way was to simply
// take the racer object from results.at(0) as this was the fastest overall time.
//Racer gc;
//if (cat1Winner.getFinishTime() != 0 ) { gc = cat1Winner; }
//if ( cat2Winner.getFinishTime() < gc.getFinishTime() && cat2Winner.getFinishTime() != 0 ) { gc = cat2Winner; }
//if ( cat3Winner.getFinishTime() < gc.getFinishTime() && cat3Winner.getFinishTime() != 0 ) { gc = cat3Winner; }
//if ( cat4Winner.getFinishTime() < gc.getFinishTime() && cat4Winner.getFinishTime() != 0 ) { gc = cat4Winner; }
//if ( cat5Winner.getFinishTime() < gc.getFinishTime() && cat5Winner.getFinishTime() != 0 ) { gc = cat5Winner; }
// declaring grand champion of the race
cout << "The Grand Champion is: \nBib\tMinutes\tAge\t\n";
cout << gc.getBibNumber() << "\t" << gc.getFinishTime() << "\t" << gc.getAge() << "\n\n";
// declaring winner from age category 1 (18-29) as long as this queue is not empty.
if ( !cat1.isEmpty() )
{
cout << "The Winner for the Age 18-29 Category is: \nBib\tMinutes\tAge\t\n";
cout << cat1Winner.getBibNumber() << "\t" << cat1Winner.getFinishTime() << "\t" << cat1Winner.getAge() << "\n\n";
}
else { cout << "\nThere were no runners in the Age 18-29 group."; }
// declaring winner from age category 2 (30-39) as long as this queue is not empty.
if ( !cat2.isEmpty() )
{
cout << "The Winner for the Age 30-39 Category is: \nBib\tMinutes\tAge\t\n";
cout << cat2Winner.getBibNumber() << "\t" << cat2Winner.getFinishTime() << "\t" << cat2Winner.getAge() << "\n\n";
}
else { cout << "\nThere were no runners in the Age 30-39 group."; }
// declaring winner from age category 3 (40-49) as long as this queue is not empty.
if ( !cat3.isEmpty() )
{
cout << "The Winner for the Age 40-49 Category is: \nBib\tMinutes\tAge\t\n";
cout << cat3Winner.getBibNumber() << "\t" << cat3Winner.getFinishTime() << "\t" << cat3Winner.getAge() << "\n\n";
}
else { cout << "\nThere were no runners in the Age 40-49 group."; }
// declaring winner from age category 4 (50-59) as long as this queue is not empty.
if ( !cat4.isEmpty() )
{
cout << "The Winner for the Age 50-59 Category is: \nBib\tMinutes\tAge\t\n";
cout << cat4Winner.getBibNumber() << "\t" << cat4Winner.getFinishTime() << "\t" << cat4Winner.getAge() << "\n\n";
}
else { cout << "\nThere were no runners in the Age 50-59 group."; }
// declaring winner from age category 5 (60-69) as long as this queue is not empty.
if ( !cat5.isEmpty() )
{
cout << "The Winner for the Age 60-69 Category is: \nBib\tMinutes\tAge\t\n";
cout << cat5Winner.getBibNumber() << "\t" << cat5Winner.getFinishTime() << "\t" << cat5Winner.getAge() << "\n\n";
}
else { cout << "\nThere were no runners in the Age 50-59 group."; }
// shows all racers in age category 1 (18-29) Or announces that there were no racers in this group.
int catSize = cat1.size();
if ( !catSize == 0 )
{
cout << "\nThe Racers in the Age 18 - 29 group are: \nBib\tMinutes\tAge\n";
for( int i=0; i<catSize; i++ ) {
Racer temp = cat1.dequeue();
cout << temp.getBibNumber() << "\t" << temp.getFinishTime() << "\t" << temp.getAge() << endl;
}
}
else { cout << "\nThere were no Racers in the Age 18-29 group.\n"; }
// shows all racers in age category 2 (30-39) Or announces that there were no racers in this group.
catSize = cat2.size();
if ( !catSize == 0 )
{
cout << "\nThe Racers in the Age 30 - 39 group are: \nBib\tMinutes\tAge\n";
for( int i=0; i<catSize; i++ ) {
Racer temp = cat2.dequeue();
cout << temp.getBibNumber() << "\t" << temp.getFinishTime() << "\t" << temp.getAge() << endl;
}
}
else { cout << "\nThere were no Racers in the Age 30-39 group.\n"; }
// shows all racers in age category 3 (40-49) Or announces that there were no racers in this group.
catSize = cat3.size();
if ( !catSize == 0 )
{
cout << "\nThe Racers in the Age 40 - 49 group are: \nBib\tMinutes\tAge\n";
for( int i=0; i<catSize; i++ ) {
Racer temp = cat3.dequeue();
cout << temp.getBibNumber() << "\t" << temp.getFinishTime() << "\t" << temp.getAge() << endl;
}
}
else { cout << "\nThere were no Racers in the Age 40-49 group.\n"; }
// shows all racers in age category 4 (50-59) Or announces that there were no racers in this group.
catSize = cat4.size();
if ( !catSize == 0 )
{
cout << "\nThe Racers in the Age 50 - 59 group are: \nBib\tMinutes\tAge\n";
for( int i=0; i<catSize; i++ ) {
Racer temp = cat4.dequeue();
cout << temp.getBibNumber() << "\t" << temp.getFinishTime() << "\t" << temp.getAge() << endl;
}
}
else { cout << "\nThere were no Racers in the Age 50-59 group.\n"; }
// shows all racers in age category 5 (60-69) Or announces that there were no racers in this group.
catSize = cat5.size();
if ( !cat5.isEmpty() )
{
cout << "\nThe Racers in the Age 60 - 69 group are: \nBib\tMinutes\tAge\n";
for( int i=0; i<catSize; i++ ) {
Racer temp = cat5.dequeue();
cout << temp.getBibNumber() << "\t" << temp.getFinishTime() << "\t" << temp.getAge() << endl;
}
}
else
{
cout << "\nThere were no Racers in the Age 60-69 group\n";
}
return 0;
}