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.
Related
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> ©This);
// 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> ©This){
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).
So i am coding a browser tab structure, and i have 5 custom class, Stack, LinkedList, Node(for linked list), Tab and Browser.
LinkedList and Stack works fine on their own, but when i construct a LinkedList in Browser's constructer i get error. So in my main i only call Browser().Here are the codes:
LinkedList<T>::LinkedList(){
front=NULL;
back=NULL;
}`
Node<T>::Node(){
prev=NULL;
next=NULL;
data=T();
}
Stack<T>::Stack(int capacity){ //capacity is optional, this is the default constructor.
this->capacity=capacity;
this->size=0;
this->items=new T[capacity];
}
`
Browser(){
selected = NULL;
//print browser link construction starts
pages= LinkedList<Tab>(); //This line gives the error.
closedPages= Stack<Tab>();
curr_index=-1;
tab_count=0;
}
Tab(){
current_page="";
prevPages=Stack<string>();
nextPages=Stack<string>();
closed_index=-1;
}
What is even funnier is that when i do print insertion, what i see is it first starts and finishes a link construction(without doing any tab construction in between), then does bunch of stack and tab construction, THEN prints the "browser link construction starts" and then goes in to and finishes another link construction and then gives seg fault. So it goes in to link construction twice even tough i hoped it would do only once?
Thanks, and sorry in advance if it is something extremly easy/stupid.
EDIT1: Full LinkedList Code
#ifndef _LINKEDLIST_H_
#define _LINKEDLIST_H_
#include <iostream>
#include <cstddef>
#include <stdexcept>
#include "Node.hpp"
using namespace std;
template <class T>
class LinkedList {
private:
/* pointer to the first node */
Node<T>* front;
/* pointer to the last node */
Node<T>* back;
public:
LinkedList();
LinkedList(const LinkedList<T>& ll);
LinkedList<T>& operator=(const LinkedList<T>& ll);
~LinkedList();
/* returns the first node of the linked list */
Node<T>& getFront() const;
/* returns the last node of the linked list */
Node<T>& getBack() const;
/* returns the node in given "pos"ition of the linked list */
Node<T>& getNodeAt(int pos) const;
/* returns the pointer of the node in given
"pos"ition of the linked list */
Node<T>* getNodePtrAt(int pos) const;
/* inserts a new node containing "data"
after the node "prev"
*/
void insert(Node<T>* prev, const T& data);
/* inserts a new node containing "data"
at "pos"ition in the linked list
*/
void insertAt(int pos, const T& data);
/* erases the given "node" from the linked list */
void erase(Node<T>* node);
/* erases the node in given "pos"ition from the linked list */
void eraseFrom(int pos);
/* clears the contents of the linked list */
void clear();
/* inserts a new node containing "data"
to the front of the linked list
*/
void pushFront(const T& data);
/* inserts a new node containing "data"
to the back of the linked list
*/
void pushBack(const T& data);
/* removes the first node */
void popFront();
/* removes the last node */
void popBack();
/* returns true if the list is empty, false otherwise */
bool isEmpty() const;
/* returns the number of items in the list */
size_t getSize() const;
/* prints the contents of the linked list
one node data per line
assumes the objects in the node have operator<< overloaded
*/
void print() const;
};
template <class T>
LinkedList<T>::LinkedList(){
cout << "list construction starts" << endl;
front=NULL;
back=NULL;
cout << "list construction ends" << endl;
}
//COPY AND ASSIGMENT
template<class T>
LinkedList<T>::LinkedList(const LinkedList<T>& ll){
*this=ll;
}
template<class T>
LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T>& ll){
clear();
Node<T>* temp=&(ll.getFront());
while(temp->getNext()!=NULL){
pushBack(temp->getData());
temp->setNext(temp->getNext());
}
pushBack(temp->getData());
return *this;
}
template<class T>
LinkedList<T>::~LinkedList(){
clear();
}
template <class T>
Node<T>& LinkedList<T>::getFront() const{
return *front;
}
template <class T>
Node<T>& LinkedList<T>::getBack() const{
return *back;
}
template <class T>
Node<T>& LinkedList<T>::getNodeAt(int pos) const{
if(pos<0 or pos>=getSize()){
throw out_of_range("Bad Input");
}
Node<T>* retval=front;
for(int i=0;i<pos;i++){
retval=retval->getNext();
}
return *retval;
}
template <class T>
Node<T>* LinkedList<T>::getNodePtrAt(int pos) const{
if(pos<0 or pos>getSize()){
throw out_of_range("Bad Input");
}
Node<T>* retval=front;
for(int i=0;i<pos;i++){
retval=retval->getNext();
}
return retval;
}
template <class T>
void LinkedList<T>::insert(Node<T>* prev,const T& data){
if(prev==NULL){
pushFront(data);
}
else if(prev==back){
pushBack(data);
}
else{
Node<T>* newNode=new Node<T>();
newNode->setData(data);
prev->getNext()->setPrev(newNode);
newNode->setNext(prev->getNext());
newNode->setPrev(prev);
prev->setNext(newNode);
}
}
template <class T>
void LinkedList<T>::insertAt(int pos,const T& data){
if(pos==0){
pushFront(data);
}
else if(pos==getSize()){
pushBack(data);
}
else{
Node<T>* tmp=getNodePtrAt(pos);
Node<T> newNode;
newNode.setData(data);
tmp->getPrev()->setNext(&newNode);
newNode.setNext(tmp);
newNode.setPrev(tmp->getPrev());
tmp->setPrev(&newNode);
}
}
template <class T>
void LinkedList<T>::pushFront(const T& data){
Node<T>* newNode=new Node<T>();
newNode->setData(data);
if(front==NULL){
front=newNode;
back=newNode;
}
else {
newNode->setNext(front);
front->setPrev(newNode);
front=newNode;
newNode->setPrev(NULL);
}
}
template <class T>
void LinkedList<T>::pushBack(const T& data){
Node<T>* newNode=new Node<T>();
newNode->setData(data);
if(front==NULL){
front=newNode;
back=newNode;
}
else {
newNode->setPrev(back);
back->setNext(newNode);
back=newNode;
newNode->setNext(NULL);
}
}
template <class T>
void LinkedList<T>::erase(Node<T>* node){
if(node==front){
popFront();
}
if(node==back){
popBack();
}
else {
node->getNext()->setPrev(node->getPrev());
node->getPrev()->setNext(node->getNext());
node->setNext(NULL); node->setPrev(NULL);
}
delete node;
}
template <class T>
void LinkedList<T>::eraseFrom(int pos){
Node<T>* tmp=getNodePtrAt(pos);
erase(tmp);
}
template <class T>
void LinkedList<T>::clear(){
while(!isEmpty()){
popFront();
}
}
template <class T>
void LinkedList<T>::popFront(){
Node<T>* tmp;
tmp=front;
if(front==back){
front=NULL;
back=NULL;
}
else{
front=front->getNext();
front->setPrev(NULL);
}
delete tmp;
}
template <class T>
void LinkedList<T>::popBack(){
Node<T>* tmp;
tmp=back;
if(front==back){
front=NULL;
back=NULL;
}
else {
back=back->getPrev();
back->setNext(NULL);
}
delete tmp;
}
template <class T>
bool LinkedList<T>::isEmpty() const{
return front==NULL;
}
template <class T>
size_t LinkedList<T>::getSize() const{
if(front==NULL){
return 0;
}
size_t size=1;
Node<T>* current=front;
while(current->getNext()!=NULL){
size++;
current=current->getNext();
}
return size;
}
template <class T>
void LinkedList<T>::print() const{
Node<T>* current=front;
if(front!=NULL){
while(current->getNext()!=NULL){
cout << current->getData() << endl;
current=current->getNext();
}
cout << current->getData() << endl;
}
}
#endif
Your assignment operator appears to be problematic. In your Browser constructor I see this:
pages = LinkedList<Tab>();
This is actually unnecessary but is triggering your problem. Your 'pages' variable is already default constructed (which is why you see all that activity before the print statement) by the time your Browser constructor code begins. Then you perform the assignment which utilizes your assignment operator.
Your assignment operator is assuming that the source LinkedList object has data, but it does not. It is calling getFront() which dereferences 'front', which is NULL. You should check if it is empty first, which I see you have a method for already (isEmpty()).
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.
I am having some trouble with my homework and could use your help.
I am getting some sort of error when I try to run my program. When i compile it i get the success mssage but when i try to run it i get a popup with the error "Unhandled exception at 0x011b18d2 in Project 2.exe: 0xC0000005: Access violation reading location 0xccccccd0." If anyone can help me i would appreciate it, thank you.
This is the code i was assigned to build on (this cannot be changed)
#include <iostream >
#include "stack.h"
using namespace std ;
int main ()
{
Stack < int > s1 , s2 ;
int element ;
s1 . push (1); s1 . push (2); s1 . push (3);
s1 . pop ( element );
cout << " s1 popped element : " << element << endl ;
s2 = s1 ;
s2 . push (4);
s2 . pop ( element );
cout << " s2 popped element : " << element << endl ;
s1 . pop ( element );
cout << " s1 popped element : " << element << endl ;
s2 . makeEmpty ();
s2 . isEmpty () ? cout << " s2 is empty \n": cout << " s2 is not empty \n ";
system ("pause");
return 0;
}
This is what i wrote to compliment the code above
template <class DataType>
struct Node{
DataType info;
Node<DataType>*next;
};
template <class DataType>
class Stack
{
public:
Stack();
void push(DataType elementToPush);
bool pop(DataType & poppedElement);
bool peek(DataType & topElement);
Stack(const Stack<DataType> &element); // Copy constructor
~Stack(); // Destructor
Stack<DataType> & operator=(const Stack<DataType> &element); //Overload assignment operator
bool isEmpty()const;
void makeEmpty();
private:
Node<DataType>*top;
Node<DataType>*header;
inline void deepCopy(const Stack<DataType> & original);
};
template<class DataType>
Stack<DataType>::Stack()
{
Node<DataType>*top=new Node<DataType>;
}
template<class DataType> // Remove the node at the front of the list and return the element
bool Stack<DataType>::pop(DataType & poppedElement)
{
Node<DataType>*ptr=top;
ptr=ptr->next;
Node<DataType>*ptr2=ptr->next;
top->next=ptr2;
poppedElement = ptr->info;
delete ptr;
return true;
}
template<class DataType> // Return the element at the front of the list wothout deleting it
bool Stack<DataType>::peek(DataType & topElement)
{
if(top->next==NULL)
return false;
topElement=top->next->info;
return true;
}
template<class DataType> // Make a new node for the element and push it to the front of the list
void Stack<DataType>::push(DataType elementToPush)
{
Node<DataType>*ptr=top;
Node<DataType>*ptr2=new Node<DataType>;
ptr2->info=elementToPush;
ptr2->next=ptr->next;
ptr->next=ptr2;
}
template<class DataType> // Check to see if the list is empty
bool Stack<DataType>::isEmpty()const
{
return top->next==NULL;
}
template<class DataType> // Empry the list out
void Stack<DataType>::makeEmpty()
{
Node<DataType>*ptr=top;
while(top->next != NULL)
{
while(ptr->next != NULL)
ptr->next;
delete ptr->next;
}
}
template<class DataType> // Deep copy
inline void Stack<DataType>::deepCopy(const Stack<DataType> & original)
{
Node<DataType>*copyptr=new Node<DataType>;
Node<DataType>*originalptr=top;
while(originalptr != NULL)
{
originalptr=originalptr->next;
copyptr->next=new Node<DataType>;
copyptr->info=originalptr->info;
}
}
template<class DataType> // Copy Constructor
Stack<DataType>::Stack(const Stack<DataType> &element)
{
deepCopy(element);
}
template<class DataType> // Destructor
Stack<DataType>::~Stack()
{
makeEmpty();
}
template<class DataType> // Overload assignment operator
Stack<DataType> & Stack<DataType>::operator=(const Stack<DataType> &element)
{
if(this == &element)
return *this;
makeEmpty();
deepCopy(element);
return *this;
}
I got pushback on my previous answer. Maybe this one will be better received. If you don't like my choice of white space, that is what pretty-printers are for. The code below is the original code reformatted. My thoughts are included as interlinear gloss.
Node is an implementation detail of your Stack. It should be scoped as a private type declaration, putting here pollutes the namespace. Also, if this class had a constructor that either initialized next to nullptr or required it to be set explicitly, some bugs, such as the one you found, would be easier to diagnose. As it stands, after Node is constructed, next can point to a random memory location.
template <class DataType>
struct Node {
DataType info;
Consider using a smart pointer here.
Node<DataType>* next; };
template <class DataType>
class Stack {
public:
Stack();
The argument should be const& to avoid extra copying.
void push(DataType elementToPush);
bool pop(DataType& poppedElement);
This can be a const method.
bool peek(DataType& topElement);
element is a poor name. The copy constructor copies an entire stack, not just an element.
Stack(const Stack<DataType>& element); // Copy constructor
~Stack(); // Destructor
Stack<DataType>& operator=(const Stack<DataType>&
element); //Overload assignment operator
bool isEmpty() const;
void makeEmpty();
private:
Consider using a smart pointer here.
Node<DataType>* top;
header is not used. It should be deleted.
Node<DataType>* header;
inline void deepCopy(const Stack<DataType>& original); };
template<class DataType>
Stack<DataType>::Stack() {
top should be initialized to nullptr in a member initialization list. The empty node you
are using here is not required, it makes you code more complex, and you end up leaking it later.
Also, this is a major bug. You are assigning to a local here, not the member variable!
Node<DataType>* top = new Node<DataType>; }
template<class DataType> // Remove the node at the front of the list and return the element
bool Stack<DataType>::pop(DataType& poppedElement) {
If you want ptr to be top->next just say that.
Node<DataType>* ptr = top;
ptr = ptr->next;
This ptr2 variable is not needed. You just need top->next = top->next->next. Also note that the empty head element is adding noise here.
Node<DataType>* ptr2 = ptr->next;
top->next = ptr2;
poppedElement = ptr->info;
delete ptr;
You need to have tested for underflow to return false in that case.
return true; }
People are pretty forgiving about comments, but it is best if they are properly spelled and punctuated.
template<class DataType> // Return the element at the front of the list wothout deleting it
bool Stack<DataType>::peek(DataType& topElement) {
if (top->next == NULL) {
return false; }
topElement = top->next->info;
return true; }
template<class DataType> // Make a new node for the element and push it to the front of the list
void Stack<DataType>::push(DataType elementToPush) {
This variable is meaningless, just use top.
Node<DataType>* ptr = top;
ptr2 can be constructed with the values you need instead of being mutated afterwards. Try auto ptr2 = new Node<DataType> { elementToPush, ptr->next };. Also, consider using a smart pointer.
Node<DataType>* ptr2 = new Node<DataType>;
ptr2->info = elementToPush;
ptr2->next = ptr->next;
ptr->next = ptr2; }
template<class DataType> // Check to see if the list is empty
bool Stack<DataType>::isEmpty()const {
return top->next == NULL; }
This function is just broken. You need to rethink it.
template<class DataType> // Empry the list out
void Stack<DataType>::makeEmpty() {
Node<DataType>* ptr = top;
while (top->next != NULL) {
One while loop will do you. Lists are linear, not square.
while (ptr->next != NULL) {
This statement has no effect; it does nothing. Your compiler should be warning about that, turn on warnings, or turn the warning level up.
ptr->next; }
delete ptr->next; } }
This is very broken too. You need to iterate over two lists, so you need two iterator variables. One iterator is the stuff you are copying and just needs to be bumped along as you read it. The other is mutating the current object and has slightly more book keeping.
template<class DataType> // Deep copy
inline void Stack<DataType>::deepCopy(const Stack<DataType>& original) {
Node<DataType>* copyptr = new Node<DataType>;
Node<DataType>* originalptr = top;
while (originalptr != NULL) {
originalptr = originalptr->next;
copyptr->next = new Node<DataType>;
copyptr->info = originalptr->info; } }
template<class DataType> // Copy Constructor
Stack<DataType>::Stack(const Stack<DataType>& element) {
deepCopy(element); }
template<class DataType> // Destructor
Stack<DataType>::~Stack() {
Note that makeEmpty does not delete your empty head node. This will leak a node.
makeEmpty(); }
template<class DataType> // Overload assignment operator
Stack<DataType>& Stack<DataType>::operator=(const Stack<DataType>&
element) {
if (this == &element) {
return *this; }
makeEmpty();
Again, your empty head node is causing pain here. Does deepCopy create the empty head node or not? Your use of it in your copy constructor seems to assume it does. Your use of it here seems to assume it does not. In fact, I think the problem is that makeEmpty does not delete your head node, if it did, both this function and your destructor would work properly.
deepCopy(element);
return *this; }
What you are seeing is a run-time error, not a build error. And your IDE reports a successful build, not your debugger. Your debugger is what allows you to trace through the program line-by-line and inspect the values of your variables.
Compare your code to the following.
template <class DataType>
struct Node {
DataType info;
Node<DataType>* next; };
template <class DataType>
class Stack {
public:
Stack();
void push(DataType elementToPush);
bool pop(DataType& poppedElement);
bool peek(DataType& topElement);
Stack(const Stack<DataType>& element);
~Stack();
Stack<DataType>& operator=(const Stack<DataType>& element);
bool isEmpty()const;
void makeEmpty();
private:
Node<DataType>* top;
inline void deepCopy(const Stack<DataType>& original); };
// Linked list stack implementation.
template<class DataType>
Stack<DataType>::Stack() {
// Head of the list. Not actually used for anything. Why is this here?
top = new Node<DataType>; }
// Remove the node at the front of the list and return the element
// Does not check for underflow.
template<class DataType>
bool Stack<DataType>::pop(DataType& poppedElement) {
Node<DataType>* ptr = top->next;
Node<DataType>* ptr2 = ptr->next;
top->next = ptr2;
poppedElement = ptr->info;
delete ptr;
return true; }
// Return the element at the front of the list without deleting it
template<class DataType>
bool Stack<DataType>::peek(DataType& topElement) {
if (top->next == NULL) {
return false; }
topElement = top->next->info;
return true; }
// Make a new node for the element and push it to the front of the list
template<class DataType>
void Stack<DataType>::push(DataType elementToPush) {
Node<DataType>* ptr2 = new Node<DataType>;
ptr2->info = elementToPush;
ptr2->next = top->next;
top->next = ptr2; }
// Check to see if the list is empty
template<class DataType>
bool Stack<DataType>::isEmpty()const {
return top->next == NULL; }
// Empty the list out
template<class DataType>
void Stack<DataType>::makeEmpty() {
while (top->next != NULL) {
Node<DataType>* ptr = top->next;
top->next = ptr->next;
delete ptr; } }
// Deep copy
template<class DataType>
inline void Stack<DataType>::deepCopy(const Stack<DataType>& original) {
Node<DataType>* origiter = original.top;
Node<DataType>* thisiter = top;
while (origiter->next != NULL) {
thisiter->next = new Node<DataType>(*(origiter->next));
origiter = origiter->next;
thisiter = thisiter->next; }
thisiter->next = NULL; }
// Copy Constructor
template<class DataType>
Stack<DataType>::Stack(const Stack<DataType>& element) {
deepCopy(element); }
// Destructor
template<class DataType>
Stack<DataType>::~Stack() {
// This leaks because the head node is still there.
makeEmpty(); }
// Overload assignment operator
template<class DataType>
Stack<DataType>& Stack<DataType>::operator=(const Stack<DataType>&
element) {
if (this == &element) {
return *this; }
makeEmpty();
deepCopy(element);
return *this; }
I cannot use std::list. The goal is to create a user defined MyList that can handle any data type. My problem is with my nested iterator class and possibly my function for overloading operator<<. I have been at this for awhile and I am stuck. Since the deadline is pretty close, I figure that I should risk my neck and ask the question here. It will be great if someone can assist me with this.
I realized that there are memory leaks in my code, but thats not my main concern at the moment.
I also realized that having so many friend function is not a good programming practice, I am planning to use getData() and setData() function to get/set the private variable within node later.
So please overlook the above 2 problems...
Error message:
"MyList.h", line 67: Error: iterator is not defined.
I'll include the whole header file just so that in case people need to see it. I'll include a comment at line 67 where the error is. Then I'll also include a section of my main function that uses the iterator to show how I am trying to set the iterator and iterate through the list.
#include<iostream>
#include<cstddef>
template<class T>
class Node
{
friend void MyList<T>::push_front(T aData);
friend void MyList<T>::push_back(T aData);
friend void MyList<T>::pop_front();
friend T MyList<T>::front();
friend void MyList<T>::print();
friend MyList<T>::~MyList();
friend std::ostream& operator<<(std::ostream&, Node<T>&);
private:
T data;
Node *next;
Node *prev;
public:
Node(T aData);
};
template<class T>
class MyList
{
Node<T> *head;
Node<T> *tail;
public:
MyList();
~MyList();
void push_front(T aData);
void push_back(T aData);
T front();
void pop_front();
void operator=(MyList<T>& another_List);
void print(); //Test function. Delete later.
class iterator
{
private:
MyList& object;
Node<T> *current;
public:
iterator(MyList<T>&, Node<T>*); // iterator a(*this, head);
// MyList<int>::iterator a = list.Begin();
iterator operator++(); // a++
iterator operator++(int); // ++a
iterator operator--();
bool operator!=(iterator);
friend std::ostream& operator<<(std::ostream&, iterator&);
};
iterator Begin();
iterator End();
};
template<class T>
std::ostream& operator<<(std::ostream& out, Node<T>& n)
{
out << *n.current << ' ';
return out;
}
template<class T>
std::ostream& operator<<(std::ostream& out, iterator& i) //ERROR
{
out << i->current << ' ';
return out;
}
template<class T>
Node<T>::Node(T aData)
{
data = aData;
}
template<class T>
MyList<T>::MyList()
{
head = NULL;
}
template<class T>
MyList<T>::~MyList()
{
Node<T> *temp;
while(head != NULL)
{
temp = head;
head = head->next;
delete temp;
}
head = NULL;
}
template<class T>
void MyList<T>::push_front(T aData)
{
if(head == NULL)
{
head = new Node<T>(aData);
head->next = tail;
head->prev = NULL;
tail->prev = head;
}
else
{
head->prev = new Node<T>(aData);
head->prev->prev = NULL;
head->prev->next = head;
head = head->prev;
}
}
template<class T>
void MyList<T>::push_back(T aData)
{
if(head == NULL)
{
head = new Node<T>(aData);
head->prev = NULL;
head->next = tail;
tail->prev = head;
}
else
{
tail->prev->next = new Node<T>(aData);
tail->prev->next->prev = tail->prev;
tail->prev->next->next = tail;
tail->prev = tail->prev->next;
}
}
template<class T>
T MyList<T>::front()
{
return head->data;
}
template<class T>
void MyList<T>::pop_front()
{
if(head == NULL)
std::cout << "The List is empty!" << endl;
else
{
head = head->next;
head->prev = NULL;
}
}
template<class T>
void MyList<T>::print()
{
while(head != NULL)
{
std::cout << "Test print function" << std::endl;
std::cout << '[' << head->data << ']' << std::endl;
head = head->next;
}
std::cout << "End of test print function" << std::endl;
}
template<class T>
MyList<T>::iterator::iterator(MyList<T>& list, Node<T>* p)
{
object = list;
current = p;
}
template<class T>
typename MyList<T>::iterator MyList<T>::iterator::operator++()
{
if(current == object.tail)
{
}
else
current = current->next;
return this;
}
template<class T>
typename MyList<T>::iterator MyList<T>::iterator::operator++(int)
{
if(current == object.tail)
{
}
else
current = current->next;
return this->prev;
}
template<class T>
typename MyList<T>::iterator MyList<T>::iterator::operator--()
{
if(current == object.head)
{
}
else
current = current->prev;
return this;
}
template<class T>
bool MyList<T>::iterator::operator!=(iterator b)
{
return (this.current == b.current);
}
template<class T>
typename MyList<T>::iterator MyList<T>::Begin()
{
return iterator(object, head);
}
template<class T>
typename MyList<T>::iterator MyList<T>::End()
{
return iterator(object, tail);
}
main.cpp
MyList<int>::iterator i = aList.Begin();
while(i != aList.End())
{
cout << i;
i++;
}
Since the definition of your iterator class is nested inside the definition of your MyList class template, for all code outside out MyList, its name is MyList<whatever>::iterator.
Perhaps you intended something slightly different in the code that contains the error though. While you've defined it as a template:
template<class T>
std::ostream& operator<<(std::ostream& out, iterator& i) //ERROR
{
out << i->current << ' ';
return out;
}
You don't seem to be using its template parameter (T) at all. Perhaps you really intended something more like:
template<class iterator>
std::ostream& operator<<(std::ostream& out, iterator& i) //ERROR
{
out << i->current << ' ';
return out;
}
In this case you don't need to supply a qualifier, since the iterator here is just referring to the template parameter. When you use this, the compiler will normally deduce the type of the iterator you actually pass.
Note that it's unnecessary but somewhat traditional to specify the iterator category in a template parameter like this, so you'd typically use something like OutIterator instead of just iterator for the template parameter.
This isn't really very generic though -- in particular, the ->current means it'll only really work for your specific iterator type. More typical code would overload operator * for the iterator type, so client code will just dereference the iterator. Also note that iterators are normally assumed to be "lightweight" enough that they're normally passed by value, not by reference.
class iterator {
// ...
T operator*() { return *current; }
};
// ...
template<class OutIt>
std::ostream& operator<<(std::ostream& out, OutIt i)
{
out << *i << ' ';
return out;
}