What i am making wrong with operator overloading? - c++

I don't understand what is wrong when I overload operator +
(purpose of this is to join 2 stacks in one new) ...
it returns "sum" of but change values for those previous.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
template <typename T>
classStack
{
private:
struct Node
{
T data;
Node *next;
} *top;
std::size_t size;
public:
Stack();
~Stack();
void push(T data);
void pop(void);
size_t get_size(void);
const Stack& operator=(const Stack &stack_obj);
const Stack operator+(const Stack &stack_obj);
void show_all_stack(void);
};
template <typename T>
const Stack<T> Stack<T>::operator+(const Stack &stack_obj)
{
Stack stack;
Node *tmp;
if (!this->size && !stack_obj.size) {
return stack;
}
if (!stack_obj.size)
{
stack.size = size;
stack.top = top;
}
else if (!size)
{
stack.size = stack_obj.size;
stack.top = stack_obj.top;
}
else
{
stack.size = size + stack_obj.size;
stack.top = new Node;
stack.top = top;
tmp = stack.top;
while (tmp->next)
tmp = tmp->next;
tmp->next = new Node;
tmp->next = stack_obj.top;
}
return stack;
}
Default constructor
template <typename T>
Stack<T>::Stack(void): top(nullptr), size(0)
{
}
Destructor
template <typename T>
Stack<T>::~Stack(void)
{
Node *next;
if (!size)
std::cout << "Stack is empty!\n";
else
{
while (top != nullptr)
{
next = top->next;
delete top;
top = next;
}
top = nullptr;
}
}
Assignment operator
template <typename T>
const Stack<T>& Stack<T>::operator=(const Stack<T> &stack_obj)
{
Node *tmp;
Node *ptr;
Node *last;
Node *new_node;
if (&stack_obj != this)
{
while (top != nullptr)
{
tmp = top;
top = top->next;
delete tmp;
}
top = nullptr;
size = stack_obj.size;
ptr = stack_obj.top;
while (ptr)
{
new_node = new Node;
new_node->data = ptr->data;
new_node->next = nullptr;
if (!top)
{
top = new_node;
last = new_node;
}
else
{
last->next = new_node;
last = new_node;
}
ptr = ptr->next;
}
}
}

Before creating functions that return Stack<T> by value, or have functions that require copy semantics for Stack<T> (as in your operator +), you need to make sure that Stack<T> is safely copyable. Right now, you are lacking a copy constructor, thus your operator + would never work correctly, even if the function itself is bug-free.
You're missing this function:
Stack::Stack(const Stack<T>&)
The easiest way to implement the copy constructor is to take most of your code out of the assignment operator, and place that into the copy constructor. More or less, the code should look something like this (the code has not been compiled or tested -- it is there to illustrate the main point of this answer):
template <typename T>
Stack<T>::Stack<T>(const Stack<T> &stack_obj) : top(nullptr), size(0)
{
Node *tmp;
Node *ptr;
Node *last;
Node *new_node;
ptr = stack_obj.top;
while (ptr)
{
new_node = new Node;
new_node->data = ptr->data;
new_node->next = nullptr;
if (!top)
{
top = new_node;
last = new_node;
}
else
{
last->next = new_node;
last = new_node;
}
ptr = ptr->next;
}
}
You have already written a destructor that should work, so we won't get into that function, but a working destructor is required for the next step -- implementation of the assignment operator.
Now that you have a copy constructor and destructor, you can now write the assignment operator. The technique used here is the copy / swap idiom
#include <algorithm>
//...
template <typename T>
Stack<T>& Stack<T>::operator=(const Stack<T> &stack_obj)
{
if ( &stack_obj != this )
{
Stack<T> temp(stack_obj);
std::swap(top, temp.top);
std::swap(size, temp.size);
}
return *this;
}
Believe it or not, this works. The code that used to be here was moved to the copy constructor, and thus the assignment operator is going to take advantage of the copy constructor.
To explain briefly, the code creates a temporary Stack<T> object from the passed-in stack_obj (this is why you need a working copy constructor). Then all that is done is to swap out the this members with the temporary members. Last, the temp dies off with the old data (this is why the destructor needs to be working correctly).
Note that you need to swap all of the members, so if you add more members to the Stack<T> class, you need to swap them in the assignment operator.
Once you have the basic 3 functions (copy, assign, destroy) written correctly, then and only then should you write functions that return Stack<T> by value, or write functions that take a Stack<T> by value.
You may have other issues with operator + that lie outside the scope of what this answer is presenting to you, but the gist of it is that your class requires that it has correct copy semantics before implementing +.

Related

Copy Constructor Error "Terminate called after throwing an instance of 'int'" [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 10 months ago.
Improve this question
The task was to create a copy constructor for a Forward_list class, and this is the code I have tried. But it keeps showing an error:
terminate called after throwing an instance of 'int'
I have been editing and changing, but I can't seem to get past that error.
class Forward_list
{
public:
class Node
{
public:
// A node will hold data of type T
T data{};
// next will point to the next node in the list
// we initialise next to nullptr
Node* next = nullptr;
// Because we have already intialised the variables
// the default constructor doesn't need to do anything
Node(){}
// if the constructor is called with just one argument.
Node(T input_data, Node* next_node= nullptr)
{
data = input_data;
next = next_node;
}
// Destructor
~Node(){}
};
private:
// private member variables for Forward_list
unsigned size_ = 0;
Node* head_ = nullptr;
public:
Forward_list(const Forward_list<T>& other);
template <typename T>
Forward_list<T>::Forward_list(const Forward_list& other) {
head_ = nullptr;
Node *prev_node = nullptr;
for(Node *other = head_; other != nullptr; other = other->next) {
Node *new_node = new Node;
new_node->data = other->data;
new_node->next = nullptr;
if (!head_)
head_ = new_node;
else
prev_node->next = new_node;
prev_node = new_node;
}
}
Nothing in this code throws an int. So it has to be in code you have not shown. Perhaps in the constructor of T?
Not that it matters, because your copy constructor does not even run its loop at all, since you are looping through the wrong list. You are starting your loop with this->head_ when you need to start it with other.head_ instead.
Also, the Node converting constructor should take its input_data parameter by const reference, and use a member initialization list, to avoid having to default-construct and then assign the data member in separate operations.
Also, the Forward_list copy constructor can be simplified.
Also, make sure you are following the Rule of 3/5/0, if you are not already doing so (you did not show that code).
Try something more like this:
class Forward_list
{
public:
class Node
{
public:
T data;
Node* next;
Node(const T &input_data, Node* next_node = nullptr);
};
Forward_list() = default;
Forward_list(const Forward_list<T>& other);
Forward_list(Forward_list<T>&& other);
~Forward_list();
Forward_list& operator=(Forward_list<T> other);
...
private:
// private member variables for Forward_list
unsigned size_ = 0;
Node* head_ = nullptr;
};
template <typename T>
Forward_list<T>::Node(const T &input_data, Node* next_node)
: data(input_data), next(next_node)
{
}
template <typename T>
Forward_list<T>::Forward_list(const Forward_list& other) {
Node **new_node = &head_;
for(Node *other_node = other.head_; other_node != nullptr; other_node = other_node->next) {
*new_node = new Node(other->data);
++size_;
new_node = &((*new_node)->next);
}
}
template <typename T>
Forward_list<T>::Forward_list(Forward_list&& other) :
head_(std::exchange(other.head_, nullptr)),
size_(std::exchange(other.size_, 0))
{
}
template <typename T>
Forward_list<T>::~Forward_list() {
Node *node = head_;
while (node) {
Node *next = node->next;
delete node;
node = next;
}
}
template <typename T>
Forward_list<T>& Forward_list<T>::operator=(Forward_list other)
{
std::swap(head_, other.head_);
std::swap(size_, other.size_);
return *this;
}

SinglyLinkedList implementation with rule of 3

I'm new to C++ and have been trying to implement a Singly Linked List, that provides an implementation the destructor, copy constructor and assignment operator. I'm running into compilation issues when trying to implement the copy constructor and the assignment operator.
Here's node.hpp
#ifndef LINKED_LIST_NODE_HPP
#define LINKED_LIST_NODE_HPP
template <typename T>
class Node{
public:
T data;
Node* next;
Node();
Node(T);
Node(const Node&);
~Node();
};
template <typename T>
Node<T>::Node(){}
template <typename T>
Node<T>:: Node(const T data): data(data), next(nullptr){}
template <typename T>
Node<T>::Node(const Node<T>& source) : data(source.data),
next(new Node)
{
(*next) = *(source.next) ;
}
template <typename T>
Node<T>::~Node(){}
#endif //LINKED_LIST_NODE_HPP
This is singly_linked_list.hpp
#ifndef LINKED_LIST_SINGLYLINKEDLIST_HPP
#define LINKED_LIST_SINGLYLINKEDLIST_HPP
#include <iostream>
#include "node.hpp"
template <typename T>
class SinglyLinkedList {
private:
Node<T>* head;
std::size_t count;
public:
SinglyLinkedList();
SinglyLinkedList(const SinglyLinkedList& source);
SinglyLinkedList& operator=(const SinglyLinkedList& source);
~SinglyLinkedList();
void insert(T);
void remove(T);
bool isEmpty();
int length();
void print();
};
template <typename T>
SinglyLinkedList<T>::SinglyLinkedList() : head(nullptr), count(0){}
template <typename T>
template <typename T>
SinglyLinkedList<T>::SinglyLinkedList(const SinglyLinkedList& source){
Node<T>* curr = source.head;
while(curr != nullptr){
Node<T>* p = new Node<T>;
p->data = curr->data;
curr = curr->next;
}
}
//template <typename T>
//SinglyLinkedList<T>::SinglyLinkedList& operator=(const SinglyLinkedList<T>& source){
// //not sure how to implment this.
//}
template <typename T>
SinglyLinkedList<T>::~SinglyLinkedList() {
if(!isEmpty()){
Node<T>* temp = head;
Node<T>* prev = nullptr;
while(temp->next != nullptr){
prev = temp;
temp = temp->next;
delete prev;
}
delete temp;
}
}
template <typename T>
bool SinglyLinkedList<T>::isEmpty() {
return head == nullptr;
}
template <typename T>
void SinglyLinkedList<T>::insert(T item) {
Node<T>* p = new Node<T>(item);
p->next = head;
head = p;
count += 1;
}
template <typename T>
void SinglyLinkedList<T>::remove(T item) {
bool present = false;
if (head->data == item){
Node<T>* temp = head;
head = head->next;
delete(temp);
count -= 1;
return;
}
Node<T>* temp = head;
while (temp->next != nullptr){
if (temp->next->data == item){
Node<T>* removable = temp->next;
temp->next = temp->next->next;
delete(removable);
present = true;
count -= 1;
break;
} else{
temp = temp->next;
}
}
if(!present){
throw std::invalid_argument("item not present in list");
}
}
template <typename T>
int SinglyLinkedList<T>::length() {
return count;
}
template <typename T>
void SinglyLinkedList<T>::print() {
if(isEmpty()){
throw std::invalid_argument("Can't print an empty list!");
}
Node<T>* temp = head;
while(temp != nullptr){
if(temp->next != nullptr){
std::cout<<temp->data;
std::cout<<"->";
}else{
std::cout<<temp->data;
}
temp = temp->next;
}
std::cout<<std::endl;
}
#endif //LINKED_LIST_SINGLYLINKEDLIST_HPP
I've commented out the copy constructor code to make this compile. What is the correct way of doing this? I'm just learning C++.
One issue that introduces complexity is that it is not well defined what the copy constructor of a node should do? Should the next field of the copy point to the next of the original, or it should create a copy of the next and point to that? The former is inadequate and error-prone, the latter would recursively create a copy of the whole list, one node at a time. This will work for lists of small size but will cause stack overflow for lists with many elements due to the depth of the recursive calls.
So to keep things simple, I wouldn't bother with copy constructor of a node.
template <typename T>
class Node {
public:
T data;
Node* next = nullptr;
Node() = default;
Node(const Node&) = delete; // since copying is not well defined, make it impossible to copy a node.
};
Copying a list is a well defined operation, so implementing the copy constructor makes sense. A mistake with your current implementation is that you allocate a new node, only to leak it later (nothing keeps track of the newly allocated node p). What you need looks more like this:
template <typename T>
SinglyLinkedList<T>::SinglyLinkedList(const SinglyLinkedList<T>& source)
: head(nullptr)
, count(0)
{
// deal with the trivial case of empty list
if (source.head == nullptr)
return;
// deal with the case where count >= 1
head = new Node<T>;
head->data = source.head->data;
head->next = nullptr;
count = 1;
Node<T>* lastCopied = source.head; // last node to be copied
Node<T>* lastAdded = head; // last node to be added to the current list
while (lastCopied->next != nullptr)
{
// create new node
Node<T>* p = new Node<T>;
p->data = lastCopied->next->data;
p->next = nullptr;
// link the newly created node to the last of the current list
lastAdded->next = p;
lastAdded = p;
// advance lastCopied
lastCopied = lastCopied->next;
count++;
}
}
Now regarding the assignment operator, luckily you can use the 'copy and swap' idiom that greatly simplifies things.
template <typename T>
SinglyLinkedList<T>& SinglyLinkedList<T>::operator =(SinglyLinkedList<T> source) // note that you pass by value.
{
std::swap(head, source.head);
std::swap(count, source.count);
return *this;
}
My answer would become too long if I tried to explain the copy and swap technique. It is a clever trick to write exception safe code and avoid duplication (implements assignment by using the copy ctor) at the same time. It is worth reading about it here.
Btw, the declaration of your class should look like this
template <typename T>
class SinglyLinkedList
{
private:
Node<T>* head = nullptr;
std::size_t count = 0;
public:
SinglyLinkedList(const SinglyLinkedList& source);
SinglyLinkedList& operator=(SinglyLinkedList source);
// other members here...
};
PS. My code assumes you are using c++11 or a later standard.
I don't like the direction this is headed. I'm going to explain how to do this approach right because it is an excellent lesson on recursion, but because it's recursion it can run the program out of Automatic storage (march off the end of the stack, most likely) with a sufficiently large list. Not cool.
The logic:
Copying a node copies the next node if there is one. This looks something like
template <typename T>
Node<T>::Node(const Node<T>& source) : data(source.data)
{
if (source.next) // if there is a next, clone it
{
next = new Node<T>(*source.next);
}
else
{
next = nullptr;
}
}
This reduces the linked list copy constructor to
template <typename T>
SinglyLinkedList<T>::SinglyLinkedList(const SinglyLinkedList& source){
head = new Node<T>(*source.head); //clone the head. Cloning the head will clone everything after
count = source.count;
}
A helper function may, uh... help here to make the Node copy constructor a bit more idiomatic
template <typename T>
Node<T> * initnext(const Node<T> & source)
{
if (source.next)
{
return new Node<T>(*source.next);
}
else
{
return nullptr;
}
}
template <typename T>
Node<T>::Node(const Node<T>& source) : data(source.data),
next(initnext(source))
{
}
but I don't think you gain much.
So... I don't like the above. What would I do instead? Something a lot like opetroch's solution above, but different enough that I'll write this up.
The node stays brutally stupid. As far as I'm concerned all a Node should ever know is how to store the payload and find other Nodes. This means the linked list should do all of the heavy lifting.
Concept 1: head is nothing but a next pointer. Once you abstract away its differences, unimportant here, you can use it exactly the same way you would next.
Concept 2: If you only know where next points, you have to do a bunch of extra book-keeping to track the previous node to update it's next. But if you take advantage of the previous's next pointing to the current node, you can throw out even more code. By tracking the previous node's next you have all of the information you need.
Concept 3: If you keep a pointer to the previous node's next, you can update that previous node's next any time you want by dereferencing it.
template <typename T>
SinglyLinkedList<T>::SinglyLinkedList(const SinglyLinkedList& obj)
{
Node<T>* tocopy = obj.head;
Node<T>** nextpp = &head; // head is a next. We are now pointing to a pointer to next
while (tocopy) // keep looping until there is no next node to copy
{
*nextpp = new Node<T>(tocopy->data); // copy source and update destination's next
nextpp = &(*nextpp)->next; // advance to point at the next of the node we just added
tocopy= tocopy->next; // get next node to copy
}
count = obj.count;
}
Because this iterates rather than recurses it doesn't eat up Automatic storage (probably the stack) and can keep going until the cows come home.
This logic can also be applied to remove
template <typename T>
void SinglyLinkedList<T>::remove(T item) {
Node<T>** temp = &head; //head is nothing but a next pointer.
// by pointing to where the next is, we don't
// need to track a previous or have special handling
// for the head node
while (*temp){ // because we now have a pointer to a pointer, we need an
// extra dereference
if ((*temp)->data == item){
Node<T>* removable = *temp;
*temp = (*temp)->next;
delete(removable);
count -= 1;
return; // no need for any special magic. Just get out.
} else{
temp = &(*temp)->next; // update the pointer to the next
}
}
// if we got here the node was not found.
throw std::invalid_argument("item not present in list");
}
And following through on head is just a next, we can also gut the destructor:
template <typename T>
SinglyLinkedList<T>::~SinglyLinkedList() {
while(head){ // if head null, list empty
Node<T>* temp = head; // cache so we can delete
head = head->next; // move head
delete temp; //delete removed node
}
}

Singly linked list assignment operator overload in C++

I've the following singly linked list implementation.
template <typename T> struct node{
node(T data):data(data),next(nullptr){}
T data;
node<T> * next;
};
template< typename T> class slist{
node<T>* head;
int size;
public:
slist(node<T>* head):head(head), size(0){}
slist(const slist<T>& rhs){
node<T>* temp = rhs.getHead();
node<T>* p = new node<T>(temp->data);
head = p;
node<T>* current = p;
while(temp != nullptr){
current = current->next;
current->data = temp->data;
}
}
~slist(){
if(head == nullptr) return;
while(head != nullptr){
node<T>* current = head;
head = head->next;
delete(current);
}
}
slist& operator= (const slist& rhs){
}
node<T>* getHead()const {
return head;
}
void insertFront(T item){
node<T>* p = new node<T>(item);
if(head == nullptr){
p = head;
size++;
return;
}
p->next = head;
head = p;
size++;
}
void insertBack(T item){
node<T>* p = new node<T>(item);
node<T>* current = head;
while(current->next != nullptr){
current = current->next;
}
current->next = p;
size++;
}
void remove(T item){
bool check = false;
node<T>* current = head;
try {
while(current != nullptr){
if(current->data == item) check = true;
current = current->next;
}
if(!check){
throw std::runtime_error("Item not in list");
}
}catch(std::runtime_error& e){
std::cout<<e.what()<<std::endl;
exit(-1);
}
current = head;
while(current != nullptr){
if(current->next->data == item){
node<T>* temp = current->next;
current->next = current->next->next;
delete(temp);
break;
}
current = current->next;
}
size--;
}
int getSize () const {
return size;
}
void printList(){
node<T>* current = head;
while(current != nullptr){
if(current->next != nullptr){
std::cout<<current->data<<"->";
}else{
std::cout<<current->data<<std::endl;
}
current = current->next;
}
}
};
Based on the current implementation of the class and the copy constructor, can someone help with the assignment operator overload. Also I'm a little confused about the copy constructor and assignment overload. What I understand is that the copy constructor creates a new list which has the same values as the old list from a old list. This the next address for all nodes will be different but the values will be the same since it's a deep copy. Is my understanding correct and then onwards what does the assignment overload do?
If you already have a copy constructor and destructor, also implement swap() and then implement your copy assignment operator in terms of these three, e.g.:
template <typename T>
slist<T>& slist<T>::operator= (slist<T> other) {
this->swap(other);
return *this;
}
Note that the argument is readily copied: unlike the copy constructor the copy assignment can take its argument by value.
With respect of the semantics:
The copy constructor creates a new object with the same value as the original, e.g.:
slist<int> sl1;
// insert elements into sl1
slist<int> sl2(sl1); // uses the copy constructor
The copy assignment replaces the value of ane existing object the value of the assigned value, e.g.
slist<int> sl1;
slist<int> sl2;
// possibly modify both sl1 and sl2
sl2 = sl1; // uses the copy assignment operator
You need to consider these cases:
copy construction, i.e. slist<int> newone = other;
copy assignment, i.e. slist<int> a; /* ... */ a = other;
Now, both of these operations make - as the name suggests - a copy of the original data structure. What exactly that means depends on how you want to implement it, but the following should - to stay close to the principle of least surprise - hold:
slist<int> a = some_generator(), b = another_generator();
slist<int> c = a;
// a == c should be true
b = a;
// a == b should be true now
modify(a);
// a == b should be false now, BUT b should be in the same state as before!
The easiest way to achieve this is by making - as you already suggested - deep copies. Thus you basically do the same as in your copy constructor. You make copies of each node, such that they have the same value as the original nodes, but are different entities.
If you're also targeting "modern C++", that is C++11 an onwards, then there's also a move constructor and a move assignment operator that you might want to implement.
As mentioned in the comments, your deep copy algorithm isn't correct: You need to make a copy of each node:
// if in assigment, delete the nodes pointed to by head first!
node<T> const * iterator = other.getHead();
if (iterator != nullptr) { // in your implementation, head could be a nullptr
node<T> * new_node = new node<T>(*iterator); // make a copy of head
head = new_node;
while (iterator->next) {
iterator = iterator->next;
node<T> * copy = new node<T>(*iterator);
new_node->next = copy;
new_node = copy;
}
new_node->next = nullptr;
}
Also, if you can, prefer smart pointers, unique_ptr in this case, instead of raw pointers.

Error on build but no compile errors

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; }

overloading the + operator in a class with a pointer member variable

I've a very simple class. It has a pointer member variable. I want to overload the + operator. But, it doesn't work! Here is my code:
#include <iostream>
using namespace std;
template <typename T>
struct Node{
Node *next;
T data;
};
template <typename T>
class stack{
protected:
Node <T> *head;
public:
stack();
~stack();
bool push(T);
stack <T> operator+ (stack <T>);
};
template <typename T>
stack<T>::stack(){
head = NULL;
}
template <typename T>
stack <T>::~stack(){
Node <T> *temp;
while(head){
temp = head;
head = head->next;
delete temp;
}
}
template <typename T>
bool stack <T>::push(T data){
Node <T> *newElem = new Node <T>;
if (!newElem) return false;
newElem->next = head;
newElem->data = data;
head = newElem;
return true;
}
template <typename T>
stack <T> stack<T>::operator+ (stack <T> stack1){
stack <T> result;
Node <T> *temp = head;
while (temp) {
result.push(temp->data);
temp = temp->next;
}
temp = stack1.head;
while (temp) {
result.push(temp->data);
temp = temp->next;
}
return result;
}
int main(){
stack <int> myStack1, myStack2, myStack3;
myStack1.push (1);
myStack1.push (2);
myStack2.push (3);
myStack2.push (4);
myStack3 = myStack1 + myStack2; // here at runtime myStack3 is not the result of myStack1 + myStack2.
return 0;
}
Could you please help me with this?
Please note that this is just for practice.
Thank you very much.
Your problem is that you are creating a copy of the right-hand side of the operator. The signature should be:
template <typename T>
stack <T> stack<T>::operator+ (const stack <T>& stack1) { ... }
so that you are only referencing stack1, not copying it.
This will fix the immediate problem you have, but long term, you also want to implement a correct copy-constructor as all copies of a stack will currently corrupt the memory as they link the same elements and the destrutor will delete them, the other stack then still references the deleted elements.
This is why you see "result" having the expected value, the copy called stack1 has not yet been deleted. But when the operator+ returns, it deletes stack1 and therefore all elements of stack1 are deleted. Not all pointers that were copied to the result that refer to elements from stack1 are invalid. This is why stack3 appears broken after the call.
See also the rule of three, read the "Managing resources" section in the answer.
Update: This is not enough as you also assign the result of operator+, again the rule of three applies as you don't have a correct assignment operator as well. You probably want to add these to your class:
template <typename T>
stack<T>::stack(const stack<T>& src)
{
// this will reverse the src, I'll leave it to you to fix the order!
head = NULL;
Node<T>* tmp = src->head;
while( tmp ) {
push( tmp->data );
tmp = tmp->next;
}
}
template <typename T>
stack<T>& stack<T>::operator=( stack<T> src ) // copy the argument is OK here!
{
stack old;
old->head = head;
head = src->head;
src->head = NULL;
}
Since you are learning, this above is a good starting point. You now have to
Implement the copy-constructor in a way that it does not reverse the order of elements
Understand how exactly the assignment operator works. I used an unusual implementation, but once you understand it, you learned a lot about object lifetime :)
You declared something else in class declaration, you wrote += instead of + in the definition:
stack <T> operator+ (stack <T>);
^
stack <T> stack<T>::operator+= (stack <T> stack1){
^^