Deep copy of a queue using assignment operator - c++

I have troubles with the pointers using my assignment opperator, it doesn't make a new qeueu, instead the new array points to the old one. So when I delete in the new queue the values in my old queue changes.
First off all I can see that my copy constructor isn't called in my main for some unknown reason, the problem is probably related with that.
Some of my main code used to illustrate the problem:
aQueue.enqueue(10);
aQueue.enqueue(20);
Queue<int> cQueue = aQueue;
cout << "aQueue: "; aQueue.printQeueue(2, 0);
cout << "cQueue: "; cQueue.printQeueue(3, 0);
cQueue.dequeue();
cout << "aQueue: "; aQueue.printQeueue(4, 1);
cout << "cQueue: "; cQueue.printQeueue(5, 1);
system("pause 4");
This is where the problems start, if I enqueue aQueue with 10 and 20 and then assign cQueue to aQueue, if I print aQueue the result is: 10 20. After that dequeue cQueue and print aQueue the result is: -179016023. If I print cQueue the result is: 20, as it should be.
The output: http://imgur.com/XBaSXAT
Here follows the functions used direct or indirect:
template <typename T>
T Queue<T>::dequeue(){
T temp = front();
Node *old = fronten;
fronten = fronten->next;
delete old;
return temp;
}
template <typename T>
Queue<T>::Queue(const T &rhs){
Node *tempfront = rhs.fronten;
while (tempfront.fronten!=rhs.back){
enqueue(tempfront);
tempfront = tempfront->next;
}
}
template <typename T>
void Queue<T>::enqueue(const T& item){
if (isEmpty()){
back = fronten = new Node(item);
}
else
back = back->next = new Node(item);
}
Node(const T &theElement, Node *n = nullptr): element(theElement), next(n) {};

You don't have at the moment copy constructor for your Queue class (or you don't show it). Yours
template <typename T> Queue<T>::Queue(const T &rhs)
is constructor for Queue from the type it stores. You need something like:
template <class T>
class Queue
{
public:
Queue( const Queue &); // copy ctor
Queue& operator=( const Queue& q); // assignment operator
//...
};

Related

Copy Constructor glitch during inserting elements into the stack

I've been given a Node and Stack class in my .h file. I have to implement the copy constructor, assignment operator and destructor and test them in a different test file. While testing the copy constructor after inserting 3 elements its displaying only one element. I don't know what's wrong; here's my .h file for your reference:
#ifndef _STACK_H
#define _STACK_H
#include <iostream>
#include <exception>
using std::ostream;
using std::cout;
using std::endl;
using std::range_error;
// Forward declarations
template <class T> class Stack;
template <class T> class Node;
template <class T> ostream& operator<<(ostream&, const Node<T>&);
// Node class for linked list
template <class T>
class Node {
friend Stack<T>;
public:
Node(T data = T(), Node<T>* next = nullptr) {
_data = data;
_next = next;
}
friend ostream& operator<< <T>(ostream& sout, const Node<T>& x);
private:
T _data;
Node* _next;
};
// Overloaded insertion operator. Must be overloaded for the template
// class T, or this won't work!
template <class T>
ostream& operator<<(ostream& sout, const Node<T>& x) {
sout << "Data: " << x._data;
return sout;
}
// Stack class. Linked-list implementation of a stack. Uses the Node
// class.
template <class T>
class Stack {
public:
// Constructor
Stack();
// Copy constructor, assignment operator, and destructor
// DO NOT IMPLEMENT HERE. SEE BELOW.
Stack(const Stack& rhs);
const Stack& operator=(const Stack& rhs);
~Stack();
void push(const T& data);
const T& top() const;
void pop();
bool empty() const; // Returns 'true' if stack is empty
void dump() const;
//Delete method used for destructor
void nullify();
private:
Node<T>* _head;
Node<T>* _temp1;
Node<T>* _temp2; //pointers
};
template <class T>
Stack<T>::Stack() {
_head = nullptr;
}
template <class T>
Stack<T>::Stack(const Stack<T>& rhs) {
if (rhs._head != nullptr) {
_head = new Node<T>(rhs._head->_data);
_temp1 = _head->_next; //temp1 would be the next one after head
//_temp2 = _temp2->_next;
while (_temp2 != nullptr) {
_temp1 = new Node<T>(_temp2->_data);
_temp1 = _temp1->_next;
_temp2 = _temp2->_next; //temp2 should be the next node after temp1
}
}
else
_head = nullptr;
}
template <class T>
const Stack<T>& Stack<T>::operator=(const Stack<T>& rhs) {
if (this != &rhs) {
nullify();
if (rhs._head != nullptr) {
_head = new Node<T>(rhs._head->_data);
_temp1 = _head->_next; //temp1 would be the next one after head
//_temp2 = _temp2->_next;
while (_temp2 != nullptr) {
_temp1 = new Node<T>(_temp2->_data);
_temp1 = _temp1->_next;
_temp2 = _temp2->_next; //temp2 should be the next node after temp1
}
}
else
_head = nullptr;
}
return *this;
}
template <class T>
Stack<T>::~Stack() {
nullify();
}
template <class T>
void Stack<T>::nullify() {
while (!empty()) {
pop();
}
}
template <class T>
void Stack<T>::pop() {
if (empty()) {
throw range_error("Stack<T>::pop(): attempt to pop from an empty stack.");
}
Node<T>* tmpPtr = _head->_next;
delete _head;
_head = tmpPtr;
}
template <class T>
bool Stack<T>::empty() const {
return _head == nullptr;
}
template <class T>
void Stack<T>::push(const T& data) {
Node<T>* tmpPtr = new Node<T>(data);
tmpPtr->_next = _head;
_head = tmpPtr;
}
template <class T>
const T& Stack<T>::top() const {
if (empty()) {
throw range_error("Stack<T>::top(): attempt to read empty stack.");
}
return _head->_data;
}
template <class T>
void Stack<T>::dump() const {
Node<T>* nodePtr = _head;
while (nodePtr != nullptr) {
cout << nodePtr->_data << endl;
nodePtr = nodePtr->_next;
}
}
#endif
While pushing 34, 67, 92 it shows only 92 for the copy constructor during output. Here's the code for which I'm testing my .h code:
#include "stack.h"
#include <iostream>
using namespace std;
using std::cout;
using std::endl;
int main()
{
cout << "Testing default constructor\n";
Stack<int> intStack;
intStack.dump();
cout << "Stack is empty initially\n\n";
intStack.push(34);
intStack.push(67);
intStack.push(92);
cout << "Testing copy constructor after inserting 92, 67 & 34: \n";
Stack<int> test1(intStack);
//cout << "Dumping intStack into Test1 & displaying it: \n";
test1.dump();
cout << "\nTesting destructor: \n";
test1.nullify();
test1.dump();
cout << "Its empty\n\n";
Stack<int> test2;
test2.push(75);
test2.push(56);
test2.push(88);
test2.push(69);
cout << "Testing assignment operator after inserting 69, 88, 56 & 75: \n";
Stack<int> test3;
test3 = test2;
test3.dump();
cout << "\nTesting destructor: \n";
test2.nullify();
test2.dump();
cout << "Its empty\n\n";
return 0;
}
I'm still not used to C++ completely so sorry for any errors.
There are several things wrong with your Stack class.
First, the copy constructor doesn't initialize all the members, and neither does your default constructor. Those need to be fixed:
template <class T>
Stack<T>::Stack() : _head(nullptr), _temp1(nullptr), _temp2(nullptr) {}
template <class T>
Stack<T>::Stack(const Stack<T>& rhs) : _head(nullptr), _temp1(nullptr), _temp2(nullptr)
{
//...
}
Once this is done, the copy constructor can be easily implemented using your other existing function, Stack::push. Your implementation is way too complicated.
template <class T>
Stack<T>::Stack(const Stack<T>& rhs) : _head(nullptr), _temp1(nullptr), _temp2(nullptr) {
Node<T>* temp = rhs._head;
while (temp)
{
push(temp->_data);
temp = temp->_next;
}
}
What is being done here? Simple -- all we are doing is taking the head of the passed-in Stack, and looping over the items calling Stack::push to add the data to the new Stack object. Since you have a push function already coded, you should be using it.
Second, note that we use a local temp variable. I doubt you need any of those _temp members in your class, but that is a different story.
Last, your assignment operator can easily be implemented, given you have a copy constructor and destructor for Stack:
template <class T>
const Stack<T>& Stack<T>::operator=(const Stack<T>& rhs) {
if (this != &rhs) {
Stack<T> temp = rhs;
std::swap(temp._head, _head);
std::swap(temp._temp1, _temp1);
std::swap(temp._temp2, _temp2);
}
return *this;
}
That technique uses copy / swap. All that is being done is to create a temporary from the passed-in Stack object, and just swap out the current contents with the temporary's contents. Then the temporary dies off with the old contents.
Given all of this, the class should work correctly. Whether it is 100% correct with all of the other functions, that again is a different issue.
Edit:
Here is a fix for the copy constructor. Note we still use existing functions to make the copy:
template <class T>
Stack<T>::Stack(const Stack<T>& rhs) : _head(nullptr), _temp1(nullptr), _temp2(nullptr) {
Node<T>* temp = rhs._head;
Stack<T> tempStack;
while (temp)
{
tempStack.push(temp->_data);
temp = temp->_next;
}
while (!tempStack.empty())
{
push(tempStack.top());
tempStack.pop();
}
}
This is not as efficient, but usually a stack data structure uses an underlying container such as vector where it is easy to reverse the underlying contents, and not based on a singly linked-list as you're using.

Overloading assignment operator in Singly Linked List

I'm learning about linked list. I created a template implementation, with a constructor, an inserter, a destructor, a copy constructor and an overloaded assignment operator. The problem is that my test programme doesn't output anything after overloading assignment operator.
For my assignment operator, I use a Clear() function to clear the list entirely before the copy. I put it in the destructor and checked that it works fine. I also checked my copy constructor and it worked fine as well.
File node.h: defines the node building block
#include <iostream>
using namespace std;
template <typename T>
struct Node{
T _item;
Node<T>* _next;
Node() {
_item = T();
_next = NULL;
}
Node(T item){
_item = item;
_next = NULL;
}
// Print the value of a node
friend std::ostream& operator <<(std::ostream& outs, const Node<T> &printMe){
outs << "[" << printMe._item << "]";
return outs;
}
};
File list.h: defines the linked list template
#include "node.h"
template <class T>
class List {
public:
// default constructor
List();
// Destructor
~List();
// Copy constructor
List(const List<T> &copyThis);
// Overloading assignment operator
List& operator =(const List& RHS);
// Insert i to the head of the linked list
Node<T>* InsertHead(T i);
// Clear a linked list
void Clear();
// Overload the output operator to print the list
template <class U>
friend ostream& operator <<(ostream& outs, const List<U>& l);
private:
Node<T>* head;
};
This header also provides the implementation of these member functions:
template <class T>
List<T>::List(){
head = NULL;
}
template <class T>
List<T>::~List(){
Clear();
}
template <class T>
List<T>::List(const List<T> &copyThis){
if (copyThis.head == NULL)
head = NULL;
else {
// Create walker for the original linked list
Node<T>* walker = copyThis.head->_next;
// Create new head node for new linked list
head = new Node<T>(copyThis.head->_item);
// Create new walker for new linked list
Node<T>* new_walker = head;
// Iterate walker and new walker and copy each item in the original list to new linked list
while (walker!= NULL) {
new_walker->_next = new Node<T>(walker->_item);
walker = walker->_next;
new_walker = new_walker->_next;
}
}
}
template <class T>
List<T>& List<T>::operator =(const List<T>& RHS){ // DOESN'T WORK
if (this != &RHS) {
this->Clear();
*this = List<T>(RHS);
}
return *this;
}
template <class T>
Node<T>* List<T>::InsertHead(T i){
Node<T>* temp = new Node<T>(i);
temp->_next = head;
head = temp;
return head;
}
// Clear a linked list
template <class T>
void List<T>::Clear(){
Node<T>* current = head;
Node<T>* next = new Node<T>;
while (current != NULL) {
next = current->_next;
delete current;
current = next;
}
head = NULL;
}
template <class U>
ostream& operator <<(ostream& outs, const List<U>& l){
Node<U>* walker = l.head;
while(walker != NULL){
outs << *walker;
outs << "->";
walker = walker->_next;
}
outs << "|||";
return outs;
}
File main.cpp: tests the classes
#include <iostream>
#include "list.h"
using namespace std;
int main() {
List<int> a;
a.InsertHead(17);
a.InsertHead(35);
a.InsertHead(6);
a.InsertHead(54);
a.InsertHead(6);
cout << a <<endl;;
List<int> b;
b.InsertHead(3);
b.InsertHead(2);
cout << b <<endl;;
a = b;
cout << a <<endl; // PROBLEM: NOTHING IS DISPLAYED
cout << b <<endl;
}
The problem I currently have is the overloading assignment operator function. Below is when I copy the whole execution from the copy constructor function and it runs.
template <class T>
List<T>& List<T>::operator =(const List<T>& RHS){
if (this != &RHS) {
this->Clear();
if (copyThis.head == NULL)
head = NULL;
else {
// Create walker for the original linked list
Node<T>* walker = copyThis.head->_next;
// Create new head node for new linked list
head = new Node<T>(copyThis.head->_item);
// Create new walker for new linked list
Node<T>* new_walker = head;
// Iterate walker and new walker and copy each item in the original list to new linked list
while (walker!= NULL) {
new_walker->_next = new Node<T>(walker->_item);
walker = walker->_next;
new_walker = new_walker->_next;
}
}
return *this;
}
The output for this is:
2->3->|||
However, when I simplify the code like below, it doesn't output anything:
template <class T>
List<T>& List<T>::operator =(const List<T>& RHS){
if (this != &RHS) {
this->Clear();
*this = List<T>(RHS);
}
return *this;
}
Can anyone tell me why it doesn't work and how to simplify it efficiently? I really appreciate it.
The problem
The assignment operator stops everything because of a stack overflow.
In fact, your implementation of the assignment operator uses itself the assignment operator, so that it calls itself recursively until the stack is exhausted:
*this = List<T>(RHS); // OUCH !!
| | |
V V V
<ListT> operator= List<T> ==> cals operator= again !!
The solution
Rewrite the operator so that it doesn't call itself.
Possibly clone every node, so to avoid that 2 lists share the same node and tha the first one that frees its node causes dangling pointers and UB for the other.
Not related, but please avoid using namespaces in headers. This is an extremely bad habit for later.
Additional tip: This article recommends some good and elegant practices for operator overloading. For the assignment operator, it suggests to use the copy constructor (as you attempt to do) but instead of assigning (your problem), swapping (to be verified, but swapping the heads in your case would certainly do the trick).

Copy queue items into another class object

When I will display the items in a queue I use the while loop
while (!queue.isEmptyQueue())
{
cout << queue.front() << " ";
queue.deleteQueue();
}
The items will be gone because of the deleteQueue() function so I cannot display it again.
How can I create a copy of the queue?
I tried the code below but it gives me errors.
queue1 = queue;
while (!queue1.isEmptyQueue())
{
cout << queue1.front() << " ";
queue1.deleteQueue();
}
I am using linkedQueue.h
#include<assert.h>
template <class Type>
struct nodeType
{
Type info;
nodeType<Type> *link;
};
template <class Type>
class linkedQueueType //: public queueADT<Type>
{
public:
const linkedQueueType<Type>& operator=(const linkedQueueType<Type>&);
bool isEmptyQueue() const;
bool isFullQueue() const;
void initializeQueue();
Type front() const;
Type back() const;
void addQueue(const Type& queueElement);
void deleteQueue();
linkedQueueType();
linkedQueueType(const linkedQueueType<Type>& otherQueue);
~linkedQueueType();
private:
nodeType<Type> *queueFront;
nodeType<Type> *queueRear;
};
template <class Type>
bool linkedQueueType<Type>::isEmptyQueue() const
{
return(queueFront == NULL);
}
template <class Type>
bool linkedQueueType<Type>::isFullQueue() const
{
return false;
}
template <class Type>
void linkedQueueType<Type>::initializeQueue()
{
nodeType<Type> *temp;
while (queueFront!= NULL)
{
temp = queueFront;
queueFront = queueFront->link;
delete temp;
}
queueRear = NULL;
}
template <class Type>
void linkedQueueType<Type>::addQueue(const Type& newElement)
{
nodeType<Type> *newNode;
newNode = new nodeType<Type>;
newNode->info = newElement;
newNode->link = NULL;
if (queueFront == NULL)
{
queueFront = newNode;
queueRear = newNode;
}
else
{
queueRear->link = newNode;
queueRear = queueRear->link;
}
}
template <class Type>
Type linkedQueueType<Type>::front() const
{
assert(queueFront != NULL);
return queueFront->info;
}
template <class Type>
Type linkedQueueType<Type>::back() const
{
assert(queueRear!= NULL);
return queueRear->info;
}
template <class Type>
void linkedQueueType<Type>::deleteQueue()
{
nodeType<Type> *temp;
if (!isEmptyQueue())
{
temp = queueFront;
queueFront = queueFront->link;
delete temp;
if (queueFront == NULL)
queueRear = NULL;
}
else
cout << "Cannot remove from an empty queue" << endl;
}
template<class Type>
linkedQueueType<Type>::linkedQueueType()
{
queueFront = NULL;
queueRear = NULL;
}
template <class Type>
linkedQueueType<Type>::~linkedQueueType()
{
initializeQueue();
}
If what you want to do is copy the queue, then a copy constructor / assignment operator is what you should have, as Martin said.
But if what you want is for the items to still be there after you go through the queue, then what your queue is missing is a way to tell how many items are in the queue.
You can cout each item and then move it to the back of the queue, that number of times.
Either way, all of these are missing for it to be a good queue implementation.
Copy constructor, assignment operator, size function.
(And technically, a queue doesn't have functionality to access the back item. So I wouldn't call this a queue with missing functionality, I would call it a linked list with missing functionality.)
Your problem is that your linkedQueueType doesn't have an assignment operator so the compiler is giving you one which just copies the pointers. You need an assignment operator which clones the elements.

copy constructor, overloaded assignment operator and deepCopy

I'm trying to create a class template for a link-list implementation of a Stack. Now I've gotten the push, pop, peek, and tested the destructor. But I'm wondering how should I add the copy constructor, overloaded assignment operator, and the deepCopy on my code. Here is what I got so far:
// Lab3.cpp
//
// Created by IvanChak on 4/3/16.
// Copyright © 2016 Space. All rights reserved.
#include <iostream>
using namespace std;
template<class T>
struct Node {
T item;
Node* next = NULL;
Node(T t = {}, Node* link = nullptr) :item{t}, next{link} { }
~Node() { delete next; }
};
template<class T>
class Stack {
public:
bool empty() const { return n == 0; }
void push(const T&);
T pop();
T peek();
~Stack();
private:
Node<T>* top = NULL;
size_t n;
};
template <class T>
class A
{
public:
A(const A &){}
A & operator=(const A& a){return *this;}
};
template<class T>
Stack<T>::~Stack() {
cout<<"Destructor, deallocate..."<<endl;
}
template<class T>
void Stack<T>::push(const T& t) {
Node<T>* previous{top};
top = new Node<T>{t,previous};
++n;
}
template<class T>
T Stack<T>::pop() {
if (empty()) {
cout << "Empty" << endl;
}
Node<T>* oldnode = top;
T t = top->item;
top = top->next;
--n;
delete oldnode;
return t;
}
template<class T>
T Stack<T>::peek() {
if (empty()) {
cout << "Empty" << endl;
}
return top->item;
}
int main(int argc, const char * argv[]) {
Stack<string> x{};
x.push("Hello");
x.push("Second");
x.push("Bye");
cout << x.peek() << endl;
x.pop();
cout << x.peek() << endl;
}
I don't know if you still need an answer or not, but if you do, you would want something like this for you copy constructor and your assignment operator:
template<class T>
Stack<T>::Stack(const Stack<T>& rhs)
{
if (rhs.top)
{
this->top = new Node<T>(rhs.top->item);
Node<T>* rhsNode = rhs.top; // This pointer is used for iterating through the "rhs" argument.
Node<T>* currentNode = this->top; // This pointer is used for iterating through "this".
n = 1;
while (rhsNode->next) // Loop untill the end of the stack has been reached.
{
++n;
currentNode->next = new Node<T>(rhsNode->next->item);
currentNode = currentNode->next;
rhsNode = rhsNode->next;
}
}
else // "rhs" is empty
{
n = 0;
this->top = nullptr;
}
}
Note: I wrote this code in a "deep copy" fashion. I can't think of any situation where it would be good to do a "shallow copy" on this type of data structure; in fact, I think it would be a very bad idea to do so. I don't automatically assume that you are planning on making your copy constructor do a "shallow copy" on your stack, but since you named the copy constructor and something about "deep copying" separately, I see it as entirely possible that you are.
I tested this code, and it worked.

c++ class template return value error

I was using eclipse to code up a queue, one function called getFirst is defined as:
template<class T>
T getFirst(){
return head->data;
}
in the main, after declaring the queue Q and input some valid data like:
Queue<int> Q;
Q.add(2);
cout << Q.getFirst() << endl;
The output is 2, which is just what I desired;
But!!! If I change the code to:
Queue<int> Q;
Q.add(2);
cout << Q.getFirst() << endl;
cout << Q.getFirst() << endl;
the output is not:
2
2
but something like:
2
2657382
after a few thoughts, I modified the code to:
Queue<int> Q;
Q.add(2);
cout << Q.getFirst();
cout << Q.getFirst() << endl;
this time it worked!! Just fine!! the output is 22, which make sense.
Can anybody kindly explain to me the problem here?
The definition of Node and Queue is generic and general :
template<typename T>
class Node{
public:
Node(T data, Node* left = 0, Node* right = 0): _data(data), _left(left), _right(right){
if(left)
left->_right = this;
if(right)
right->_left = this;
}
Node(): _right(0){}
private:
T _data;
Node<T>* _left;
Node<T>* _right;
friend class Queque<T>;
};
template<typename T>
class Queque{
public:
Queque(): _first(new Node<T>), _size(0){
_first->_right = _first;
_first->_left = _first;
}
void addFirst(T item){
Node<T>(item, _first, _first->_right);
_size++;
}
T examineFirst(){
return _first->_right->_data;
}
private:
Node<T>* const _first;
int _size;
};
void addFirst(T item){
Node<T>(item, _first, _first->_right);
_size++;
}
Node is a stack variable, and it's constructor will change _first, and first->_right to be pointing to some stack address, which will lead for unpredicted results, in your example usage << endl; modified stack, leading to some garbage output. To fix this you need to use new for new nodes allocation and, of course free them later with delete.