How can you implement a copy constructor for ADT queue

E

ecestd

how do you implement a copy constructor for this pointer-based ADT
queue

#include <cassert> // for assert
#include <new> // for bad_alloc

using namespace std;
//private:{Queue::Queue(const Queue& Q)}


Queue::Queue() : backPtr(0), frontPtr(0)
{
} // end default constructor

Queue::Queue(const Queue& Q) throw(OutOfStorageException)
{




/////////// Implementation
here!!!!!!///////////////








} // end copy constructor

Queue::~Queue()
{
while (!isEmpty() )
{
dequeue();
} // end while
assert ( (backPtr == 0) && (frontPtr == 0) );
} // end destructor

bool Queue::isEmpty() const
{
return backPtr == 0;
} // end isEmpty

void Queue::enqueue(const QueueItemType& newItem)
throw(OutOfStorageException)
{
try
{
QueueNode *newPtr = new QueueNode;

newPtr->item = newItem;

newPtr->next = 0;

if (isEmpty() )
{
frontPtr = newPtr;
}
else
{
backPtr->next = newPtr;
} // end if

backPtr = newPtr;
}
catch(bad_alloc e)
{
throw OutOfStorageException("Memory allocation failed.");
} // end try/catch
} // end enqueue

void Queue::dequeue() throw(OutOfDataException)
{
if (isEmpty() )
{
throw OutOfDataException("Empty queue, cannot dequeue");
}
else
{ // queue is not empty; remove front
QueueNode *tempPtr = frontPtr;
if (frontPtr == backPtr) // special case?
{ // yes, one node in queue
frontPtr = 0;
backPtr = 0;
}
else
{
frontPtr = frontPtr->next;
} // end if
tempPtr->next = 0; // defensive strategy
delete tempPtr;
} // end if
} // end dequeue

void Queue::dequeue(QueueItemType& queueFront)
throw(OutOfDataException)
{
if (isEmpty() )
{
throw OutOfDataException("Empty queue, cannot dequeue");
}
else
{ // queue is not empty; retrieve front
queueFront = frontPtr->item;
dequeue(); // delete front
} // end if
} // end dequeue

void Queue::getFront(QueueItemType& queueFront) const
throw(OutOfDataException)
{
if (isEmpty() )
{
throw OutOfDataException("Empty queue, cannot getFront");
}
else
{
// queue is not empty; retrieve front
queueFront = frontPtr->item;
} // end if
} // end getFront
 
G

Guest

how do you implement a copy constructor for this pointer-based ADT
queue

#include <cassert> // for assert
#include <new> // for bad_alloc

using namespace std;
//private:{Queue::Queue(const Queue& Q)}


Queue::Queue() : backPtr(0), frontPtr(0)
{
} // end default constructor

Queue::Queue(const Queue& Q) throw(OutOfStorageException)
{

Use Q.frontPtr to get the fist node in the other queue and start copying
elements from there.
void Queue::dequeue(QueueItemType& queueFront)

I do not see the point of this function, the exception safe way is to
use a combination of getFront() and dequeue() to remove elements from
the queue.
void Queue::getFront(QueueItemType& queueFront) const

Make this one return the first object instead of returning it through a
reference (or at the very least make the parameter a pointer instead of
a reference).
 
A

Alf P. Steinbach

* ecestd:
how do you implement a copy constructor for this pointer-based ADT
queue

typedef std::queue<QueueItemType> Queue;

Otherwise, iterate through all elements and add them to the new queue.

#include <cassert> // for assert
#include <new> // for bad_alloc

using namespace std;
//private:{Queue::Queue(const Queue& Q)}


Queue::Queue() : backPtr(0), frontPtr(0)
{
} // end default constructor

Queue::Queue(const Queue& Q)

Preferentially reserve all uppercase names for macros (one exception is
the idiom of nameing a template parameter T).

throw(OutOfStorageException)
{

It's not a good idea to use exception specifications other than the
empty one, and even that is by some regarded as Not A Good Idea.

/////////// Implementation
here!!!!!!///////////////

What's the problem?

} // end copy constructor

Queue::~Queue()
{
while (!isEmpty() )
{
dequeue();
} // end while
assert ( (backPtr == 0) && (frontPtr == 0) );
} // end destructor

bool Queue::isEmpty() const
{
return backPtr == 0;
} // end isEmpty

void Queue::enqueue(const QueueItemType& newItem)
throw(OutOfStorageException)
{
try
{
QueueNode *newPtr = new QueueNode;

newPtr->item = newItem;

This requires QueueItemType to be assignable. It's an unnecessary
requirement. Instead, pass newItem to the QueueNode constructor.

newPtr->next = 0;

if (isEmpty() )
{
frontPtr = newPtr;
}
else
{
backPtr->next = newPtr;
} // end if

backPtr = newPtr;
}
catch(bad_alloc e)

Catch by reference, preferentially reference to const.

{
throw OutOfStorageException("Memory allocation failed.");

It's not a good idea to translate a standard exception to a custom one
that means the same.

} // end try/catch
} // end enqueue

void Queue::dequeue() throw(OutOfDataException)
{
if (isEmpty() )
{
throw OutOfDataException("Empty queue, cannot dequeue");
}
else
{ // queue is not empty; remove front

Generally it doesn't add any clarity to use an 'else' where it's not
needed, because its presence indicates that it is needed, hence it just
obscures.

QueueNode *tempPtr = frontPtr;
if (frontPtr == backPtr) // special case?
{ // yes, one node in queue
frontPtr = 0;
backPtr = 0;
}
else
{
frontPtr = frontPtr->next;
} // end if
tempPtr->next = 0; // defensive strategy

Don't do "defensive strategy". You're introducing something that
seemingly can be relied on but can't be relied on. It's just an
invitation to disaster.

delete tempPtr;
} // end if
} // end dequeue

void Queue::dequeue(QueueItemType& queueFront)
throw(OutOfDataException)
{
if (isEmpty() )
{
throw OutOfDataException("Empty queue, cannot dequeue");
}
else
{ // queue is not empty; retrieve front
queueFront = frontPtr->item;
dequeue(); // delete front
} // end if
} // end dequeue

This design requires the client code to declare a variable just in order
to dequeue.

Consider at least adding a wrapper that returns the front item as
function result.

void Queue::getFront(QueueItemType& queueFront) const
throw(OutOfDataException)
{
if (isEmpty() )
{
throw OutOfDataException("Empty queue, cannot getFront");
}
else
{
// queue is not empty; retrieve front
queueFront = frontPtr->item;
} // end if
} // end getFront

Ditto.

Cheers, & hth.,

- Alf
 
E

ecestd

///////////
what to put here so that it copies. I left this blank coz this is
where it has to be implemented. The program runs but then it crashes
if you type a string. Also what is the significance of cerr<<"type
whatever you want" <<endl? . The prorum after it runs it breaks at
this point tempPtr->next = 0; // defensive strategy
 
E

ecestd

* ecestd:


typedef std::queue<QueueItemType> Queue;

Otherwise, iterate through all elements and add them to the new queue.





Preferentially reserve all uppercase names for macros (one exception is
the idiom of nameing a template parameter T).


It's not a good idea to use exception specifications other than the
empty one, and even that is by some regarded as Not A Good Idea.


What's the problem?

///////////
what to put here so that it copies. I left this blank coz this is
where it has to be implemented. The program runs but then it crashes
if you type a string. Also what is the significance of cerr<<"type
whatever you want" <<endl? . The prorum after it runs it breaks at
this point tempPtr->next = 0; // defensive strategy
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,113
Latest member
Vinay KumarNevatia
Top