GIDForums  

Go Back   GIDForums > Computer Programming Forums > C++ Forum
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 05-Oct-2005, 11:45
greymalkin greymalkin is offline
New Member
 
Join Date: Oct 2005
Location: near Houston, TX
Posts: 10
greymalkin is on a distinguished road

C++ Copy Constructor & Exception issues


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
CPP / C++ / C Code:
#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
CPP / C++ / C Code:

#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
CPP / C++ / C Code:
* 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
CPP / C++ / C Code:
#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;
}
  #2  
Old 05-Oct-2005, 14:27
QED's Avatar
QED QED is offline
Member
 
Join Date: Feb 2005
Location: Hudson Valley, NY
Posts: 231
QED is a jewel in the roughQED is a jewel in the roughQED is a jewel in the rough

Re: C++ Copy Constructor & Exception issues


Throwing an exception is great, but if there is no code to catch the exception (for example, in main()) then the program will simply terminate at that point. This is likely the "crash" you described.

If you were hoping to see those useful messages you defined, then you need to place your code (or at least the relevant portions) within a try-catch structure. That is, something like the following:
CPP / C++ / C Code:
int main()
{
    try
    {
        // your code here
    }
    catch (std::runtime_error &e)
    {
        std::cerr << e.what() << std::endl;
    }
}
No when the pesky exception goes flying, it won't wreak total havoc. You now have an exception-handler that will get thing under control and terminate a little more gracefully with that message.

I'll look into that copy constructor thing an get back to you.

-Matthew-

P.S. By capturing the exception and seeing the message, I suspect you might find out what is going wrong in your copy constructor, if it results from one of those two conditions.
  #3  
Old 05-Oct-2005, 15:21
greymalkin greymalkin is offline
New Member
 
Join Date: Oct 2005
Location: near Houston, TX
Posts: 10
greymalkin is on a distinguished road

Re: C++ Copy Constructor & Exception issues


awesome..i put the catch QueueEmptyException around my little problem child and it did exactly as it should.

catch (QueueFullException &e )
{ cout << e.what() << endl; } - did the trick.

a try/catch doesn't work on the queues i try to copy cause the copy operation actually goes through...it just barfs at the end after the output is spit out...so i cant seem to connect the copy operations with the crashing at the end although that has to be what is causing it because as soon as i comment the copy lines out it works beautifully again...

thanks for your time and help so far! I really am beginning to get the hang of this, but it's still intimidating to me...
  #4  
Old 05-Oct-2005, 22:36
greymalkin greymalkin is offline
New Member
 
Join Date: Oct 2005
Location: near Houston, TX
Posts: 10
greymalkin is on a distinguished road

Re: C++ Copy Constructor & Exception issues


well i believe i may have figured it out..miracles can happen...

it turns out i had a logic error in my main.cpp that wouldn't hold up with different situations. There were times when i would call the first() of one of my catWinner queues when the queue was empty. according ot my first() definition this throws a QueueEmptyException. I simply made a few conditions to prevent that from happening and poof! everything else worked. My program is now running stable with all features the teacher asked for being implemented...thanks for your time!
 
 

Recent GIDBlogOnce again, no time for hobbies by crystalattice

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Circular Linked Queue Copy Constructor and Assignment Operator Not Working? wc3promet C++ Forum 1 06-Oct-2008 04:00
going crazy over file copy ! w332 C++ Forum 1 22-Jul-2004 23:46
Streamyx (DSL) and Windows ME issues. JdS Computer Software Forum - Windows 4 03-Apr-2004 05:15
Downloadable document compatibilty issues? rhino1616 Web Design Forum 3 07-May-2003 04:05

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 00:41.


vBulletin, Copyright © 2000 - 2009, Jelsoft Enterprises Ltd.