Overloading operator<< for user defined MyList - c++

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

Related

Exception thrown: write access violation. prev_ptr was 0x4

I am learning about linked lists, and I decided to try implementing linked lists in C++ on my own.
I made a Node class with attributes int val and Node* ptr.
Then I made a Linked_list class with the attribute first_node, and the constructor functions work.
The append() function 'appends' a node to the list (like in Python). I first thought of just making ptr a reference to the node's pointer and then changing it when its null, but references once made, can't be changed to refer to any other variable, so I made another variable prev_ptr that points to the Node's pointer (which makes it a Node**).
Every loop, it checks if ptr is NULL, if not, ptr and prev_ptr get updated to the next Node's pointer value, and the address of the next Node's pointer value, respectively.
This keeps happening until it finds a null pointer, and then changes it to the inputted node's address.
But I'm getting an error saying:
Exception thrown: write access violation. prev_ptr was 0x4.
I can't figure out what is wrong.
Classes:
#include <iostream>
#include <string>
#include <cmath>
class Node {
public:
int val;
Node* ptr = nullptr;
Node(int Val = NULL) {
val = Val;
}
};
class Linked_list {
public:
Node first_node;
Linked_list(int F) {
Node f(F);
first_node = f;
}
void append(Node& element) {
Node* ptr = first_node.ptr;
Node** prev_ptr = &first_node.ptr;
while (true) {
if (ptr == nullptr) {
*prev_ptr = &element;
break;
}
ptr = (*ptr).ptr;
prev_ptr = &((*ptr).ptr);
}
}
};
main()
int main() {
Linked_list list(5);
Node three(3);
list.append(three);
Node four(4);
list.append(four);
return 0;
}
ptr = (*ptr).ptr;
prev_ptr = &((*ptr).ptr);
First you advance ptr to the next node. Then, you use ptr again forgetting that it has already been advanced: (*ptr).ptr now points two nodes forward, and we don't know if we can go that much far.
Perhaps you need to swap the assignments.
prev_ptr = &((*ptr).ptr);
ptr = (*ptr).ptr;
(Further, why not ptr->ptr?)
Okay, you're doing a few things in an odd fashion. First, your Linked_List should probably NOT have a Node for firstNode. It should have a Node *. After all, an empty list is possible. So is (normally) deleting the first node. Also, there's an informal naming convention of calling it head. There's also a standard convention of calling the link in your Node next rather than ptr.
But there are two simpler methods for your append() method. First, you can also keep a Node * tail in Linked_List. This is common. It points to the last node in the list. If you do that, then append looks like:
void append(Node &nodeToAppend) {
if (head == nullptr) {
head = &nodeToAppend;
tail = &nodeToAppend;
}
else {
tail->next = nodeToAppend;
tail = &nodeToAppend;
}
}
However, it's also worthwhile to be able to insert anywhere or append without a tail:
void append(Node &nodeToAppend) {
if (head == nullptr) {
head = &nodeToAppend;
}
else {
Node *ptr = head;
while (ptr->next != nullptr) {
ptr = ptr->next;
}
ptr->next = &nodeToAppend;
}
}
An insert in some sort of sorted order would be nearly identical, although slightly different. The while-loop would look like:
while (ptr->next != nullptr && ptr->value < nodeToAppend.value) ...
but would otherwise be identical.
This code doesn't solve your immediate issue, but answers a question raised in the comments.
Linked lists are usually (where I taught) a 300-400 level assignment. There are a lot of principles that one must be competent in to write a decent linked list. First, I'll show the main.cpp and its output.
main.cpp
#include "list.hpp"
#include <iostream>
template <typename Container>
void print(Container& container, std::ostream& sout = std::cout)
{
for (auto i : container) {
sout << i << ' ';
}
sout << '\n';
}
int main()
{
List<int> list;
for (int i = 1; i <= 10; ++i) {
list.push_back(i);
}
print(list);
list.erase(list.find(4));
print(list);
list.erase(list.find(1));
print(list);
list.erase(list.find(10));
print(list);
}
Output:
1 2 3 4 5 6 7 8 9 10
1 2 3 5 6 7 8 9 10
2 3 5 6 7 8 9 10
2 3 5 6 7 8 9
It doesn't test every aspect of the linked list, but it serves to demonstrate what a user should be expected to work with. Users will want to interact directly with the list and its iterators in C++. You create a Node, and then add the Node to your list. That's a level of DIY that no user wants to be bothered with. In the code below, you'll see that a Node is still used, but it only exists within the List class. Users will never see a Node.
You can look in functions like push_back() (similar to your append) for specific answers related to your question.
To explain it a bit more, the pointers are key. Yes, I declare a local Node* that will go out of scope, but the object created continues to exist on the heap. And the list is able to keep track of these Nodes due to how linked lists work, namely that the Nodes know where their neighbors live (hold their addresses).
There is also a List<T>::iterator class. In the declaration, functions marked as // minimum are required if you want to use your linked list in a range-based for loop. The other functions do work toward satisfying the requirements of LegacyBidirectionalIterator; this is the level of iterator used by std::list in the C++ Standard Library.
The code below should only be considered a decent example (Hopefully not too presumptuous on my part). It is lacking some functionality that's found in std::list, and likely does a few things in non-optimal manners. A big thing that will need tweaking is removing the member function find() and make the class work with std::find().
list.hpp
#ifndef MY_LIST_HPP
#define MY_LIST_HPP
#include <algorithm> // std::swap
#include <cstddef> // std::size_t
/*
* Pre-declare template class and friends
*/
template <typename T>
class List;
template <typename T>
void swap(List<T>& lhs, List<T>& rhs);
/*
* List Class Declaration
*/
template <typename T>
class List {
public:
List() = default;
List(T val);
List(const List& other);
List(List&& other);
~List();
void push_front(T val);
void push_back(T val);
class iterator;
iterator begin();
iterator end();
iterator find(T val);
std::size_t size() const;
iterator erase(iterator toErase); // Implement
void clear();
bool operator=(List other);
friend void swap<T>(List& lhs, List& rhs);
private:
struct Node {
T data;
Node* prev = nullptr;
Node* next = nullptr;
Node(T val) : data(val) {}
};
Node* m_head = nullptr;
Node* m_tail = nullptr;
std::size_t m_size = 0;
// Helper functions
void make_first_node(T val);
Node* find_node(T val);
};
/*
* List Iterator Declaration
*/
template <typename T>
class List<T>::iterator {
public:
iterator() = default;
iterator(List<T>::Node* node); // minimum
T& operator*(); // minimum
iterator& operator++(); // minimum
iterator operator++(int);
iterator& operator--();
iterator operator--(int);
bool operator==(const iterator& other); // minimum
bool operator!=(const iterator& other); // minimum
private:
Node* m_pos = nullptr;
};
/*
* List Implementation
*/
template <typename T>
List<T>::List(T val) : m_head(new Node(val)), m_tail(m_head), m_size(1) {}
template <typename T>
List<T>::List(const List<T>& other) {
m_head = new Node((other.m_head)->data);
m_tail = m_head;
m_size = 1;
Node* walker = (other.m_head)->next;
while (walker) {
push_back(walker->data);
++m_size;
walker = walker->next;
}
}
template <typename T>
List<T>::List(List&& other) : List() {
swap(*this, other);
}
template <typename T>
List<T>::~List() {
clear();
}
template <typename T>
void List<T>::push_front(T val)
{
if (!m_head) {
make_first_node(val);
return;
}
Node* tmp = new Node(val);
tmp->next = m_head;
m_head->prev = tmp;
m_head = tmp;
++m_size;
}
template <typename T>
void List<T>::push_back(T val) {
if (!m_head) {
make_first_node(val);
return;
}
Node* tmp = new Node(val);
tmp->prev = m_tail;
m_tail->next = tmp;
m_tail = tmp;
++m_size;
}
template <typename T>
typename List<T>::iterator List<T>::begin() {
return iterator(m_head);
}
template <typename T>
typename List<T>::iterator List<T>::end() {
return iterator(nullptr);
}
template <typename T>
typename List<T>::iterator List<T>::find(T val) {
return iterator(find_node(val));
}
template <typename T>
std::size_t List<T>::size() const {
return m_size;
}
template <typename T>
typename List<T>::iterator List<T>::erase(typename List<T>::iterator toErase)
{
Node* node = find_node(*toErase);
if (node->prev) {
node->prev->next = node->next;
} else {
m_head = node->next;
}
if (node->next) {
node->next->prev = node->prev;
} else {
m_tail = node->prev;
}
Node* toReturn = node->next;
delete node;
return toReturn;
}
template <typename T>
void List<T>::clear() {
Node* tmp = m_head;
while (m_head) {
m_head = m_head->next;
delete tmp;
tmp = m_head;
}
m_tail = nullptr;
m_size = 0;
}
template <typename T>
bool List<T>::operator=(List other) {
swap(*this, other);
return *this;
}
template <typename T>
void List<T>::make_first_node(T val) {
m_head = new Node(val);
m_tail = m_head;
m_size = 1;
}
template <typename T>
typename List<T>::Node* List<T>::find_node(T val) {
if (!m_head) {
return nullptr;
}
Node* walker = m_head;
while (walker != nullptr && walker->data != val) {
walker = walker->next;
}
return walker;
}
template <typename T>
void swap(List<T>& lhs, List<T>& rhs) {
using std::swap;
swap(lhs.m_head, rhs.m_head);
swap(lhs.m_tail, rhs.m_tail);
swap(lhs.m_size, rhs.m_size);
}
/*
* List Iterator Implementation
*/
template <typename T>
List<T>::iterator::iterator(Node* node) : m_pos(node) {}
template <typename T>
T& List<T>::iterator::operator*() {
return m_pos->data;
}
template <typename T>
typename List<T>::iterator& List<T>::iterator::operator++() {
m_pos = m_pos->next;
return *this;
}
template <typename T>
typename List<T>::iterator List<T>::iterator::operator++(int) {
iterator tmp(m_pos);
++(*this);
return tmp;
}
template <typename T>
typename List<T>::iterator& List<T>::iterator::operator--() {
m_pos = m_pos->prev;
return *this;
}
template <typename T>
typename List<T>::iterator List<T>::iterator::operator--(int) {
iterator tmp(m_pos);
--(*this);
return tmp;
}
template <typename T>
bool List<T>::iterator::operator==(const iterator& other) {
return m_pos == other.m_pos;
}
template <typename T>
bool List<T>::iterator::operator!=(const iterator& other) {
return !(*this == other);
}
#endif
Code and explaination
I think this code should work as well, so there is no need to have two pointers. It's based on an example of “good taste” that Linus Torvalds gave in an interview.
void append(Node &element)
{
Node** cursor = &first_node.ptr;
while ((*cursor) != nullptr)
cursor = &(*cursor)->ptr;
*cursor = &element;
}
It eliminates the need for multiple pointers, it eliminates edge cases and it allows us to evaluate the condition of the while loop without having to let go of the pointer that points to the next element. This allows us to modify the pointer that points to NULL and to get away with a single iterator as opposed to ptr and prev_ptr.
Naming conventions
Also the norm is to call the first node in the linked list head and to call the pointer to the next node next instead of ptr, so I will rename them in the following code.
void append(Node &new)
{
Node** cursor = &head.next;
while ((*cursor) != nullptr)
cursor = &(*cursor)->next;
*cursor = &new;
}

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.

Operator<< in C++ with custom Data Structures

I'm trying to make a custom set of header files to use a generic List and use operator<< to make it print into a ostream object
There are a couple of errors which I cannot resolve.
I'm trying to make a generic List class using a generic Node class. The generic List should be printed using the operator<< . However I'm getting a lot of errors.
#include <iostream>
using std::cout;
using std::ostream;
class List;
template<class T>
class Node
{
friend class List<Node>;
private:
T data_;
Node *next_;
public:
Node(T data);
T get_data();
};
template<typename T>
Node<T>::Node(T data)
{
data_ = data;
next_ = 0;
}
template<typename T>
T Node<T>::get_data()
{
return data_;
}
template<typename T>
class Node;
template<typename T>
class List
{
template<typename T>
friend ostream& operator<<(ostream& o , const List<T> head);
private:
Node<T> *start_;
bool is_empty();
public:
List();
~List();
void insert(T data);
void remove();
};
template<typename T>
bool List<T>::is_empty()
{
if(start_ == 0)
return true;
return false;
}
template<typename T>
List<T>::List()
{
start_ = 0;
}
template<typename T>
List<T>::~List()
{
if( !is_empty())
{
Node<T> *current = start_;
Node<T> *temp;
while(current != 0)
{
temp = current;
current = current->next_;
delete temp;
}
}
}
template<typename T>
void List<T>::insert(T data)
{
if(is_empty())
{
Node<T> *temp = new Node<T>(data);
start_ = temp;
}
else
{
Node<T> *temp = start_;
while(temp->next_ != 0)
{
temp = temp->next_;
}
temp->next_ = new Node<T>(data);
}
}
template<typename T>
void List<T>::remove()
{
if(start_->next_ == 0)
{
Node<T> *temp = start_->next_;
start_->next_ = 0;
delete temp;
}
else if(!is_empty())
{
Node<T> *stay = start_;
Node<T> *remove = stay->next_;
while(remove->next_ != 0)
{
stay = remove;
remove = remove->next_;
}
stay->next_ = 0;
delete remove;
}
}
// Experimental Stuff out here
template<typename T>
ostream& operator<<(ostream& o , const List<T> *head)
{
Node<T> *temp = head->start_;
if(!is_empty<T>())
{
while(temp->next_ != 0)
{
o << temp.get_data() << "\t";
o << "\n";
temp = temp->next_;
}
}
return o;
}
// End of Experimental Stuff
Assuming clients of your class instantiate it like this:
List<int> my_list;
You need to define your operator << overload like this:
template <typename T>
std::ostream& operator << (std::ostream& os, const List<T>& list)
{
// I'm gonna assume you have C++11
auto node = list.start_;
while (node != nullptr)
{
os << '\t' << node->get_data() << '\n';
node = node->next_;
}
return os;
}
Additionally, there are loads of errors in your code regarding templates, so please fix them first.

Overloading the dereference operator for a custom iterator

This is the first time I've ever played with an iterator so there's probably significant errors. I'm attempting to make an inorder iterative iterator class to work in conjunction with my threaded binary search tree. So the iterator is working over nodes. I only need the iterator to go through my tree in order so I can print all the values and the frequencies of each node. However my dereference doesn't seem to be working probably. This is the method that's giving me trouble:
//-------------------------- inOrderTraverse ------------------------------------
template <typename T>
void ThreadedBST<T>::inOrderTraverse() {
InorderIterator<T>* iter = new InorderIterator<T>(root);
++iter;
while ((*iter) != NULL)
{
cout << (*iter)->getItem() << " " << (*iter)->getFrequency() << endl;
}
}
Particularly the while loop is throwing compiler errors. Here is the exact error:
error C2678: binary '!=' : no operator found which takes a left-hand operand of type 'InorderIterator'
I figured the dereference would bring the node out so I'd actually be comparing the node != NULL but that's not what the error message leads me to believe. Here's the full Iterator class:
#ifndef INORDERITER_H
#define INORDERITER_H
#include <iostream>
#include "ThreadedBST.h"
using namespace std;
//---------------------------------------------------------------------------
// InorderIterator<T> class:
// --
//
// Assumptions:
// -- <T> implements it's own comparable functionality
//---------------------------------------------------------------------------
template <typename T>
class InorderIterator {
public:
InorderIterator(node<T> *); //constructor
InorderIterator<T>& operator++();
node<T>& operator*();
const node<T>& operator*() const;
private:
node<T>* begin;
node<T>* curr;
node<T>* prev;
node<T>* temp;
};
template <typename T>
InorderIterator<T>::InorderIterator(node<T>* root) {
begin = root;
temp = NULL;
while (begin->leftChild != NULL) {
begin = begin->leftChild;
}
}
template <typename T>
InorderIterator<T>& InorderIterator<T>::operator++() {
if (temp == NULL)
temp = begin;
else if (rightChildThread) {
prev = temp;
temp = temp->rightChild;
}
else {
prev = temp;
temp = temp->rightChild;
while (!temp->rightChildThread && (temp->leftChild->getItem() != prev->getItem())) {
temp = temp->leftChild;
}
}
curr = temp;
return *this;
}
template <typename T>
node<T>& InorderIterator<T>::operator*() {
return *curr;
}
template <typename T>
const node<T>& InorderIterator<T>::operator*() const {
return *curr;
}
#endif
Here's the node class if it's relevant for any reason:
#ifndef NODE_H
#define NODE_H
#include <iostream>
using namespace std;
//---------------------------------------------------------------------------
// node<T> class:
// --
//
// Assumptions:
// -- <T> implements it's own comparable functionality
//---------------------------------------------------------------------------
template <typename T>
class node {
public:
node<T>* leftChild;
node<T>* rightChild;
bool leftChildThread;
bool rightChildThread;
node(T value); //constructor
node(T value, node<T>*, node<T>*, bool, bool); //secondary constructor
node(const node<T>&); //copy constructor
void decrementFrequency(); //decrements by 1 the frequency
void incrementFrequency(); //increments by 1 the frequency
int getFrequency(); //returns the frequency
T getItem(); //returns the item
private:
T item;
int frequency;
};
//-------------------------- Constructor ------------------------------------
template <typename T>
node<T>::node(T value) {
item = value;
frequency = 1;
}
//-------------------------- Secondary Constructor ------------------------------------
template <typename T>
node<T>::node(T value, node<T>* left, node<T>* right, bool leftThread, bool rightThread) {
item = value;
frequency = 1;
leftChild = left;
rightChild = right;
leftChildThread = leftThread;
rightChildThread = rightThread;
}
//-------------------------- Copy ------------------------------------
template <typename T>
node<T>::node(const node<T>& copyThis) {
item = copyThis.value;
frequency = copyThis.frequency;
}
//-------------------------- decrementFrequency ------------------------------------
template <typename T>
void node<T>::decrementFrequency() {
frequency--;
}
//-------------------------- incrementFrequency ------------------------------------
template <typename T>
void node<T>::incrementFrequency() {
frequency++;
}
//-------------------------- getFrequency ------------------------------------
template <typename T>
int node<T>::getFrequency() {
return frequency;
}
//-------------------------- getItem ------------------------------------
template <typename T>
T node<T>::getItem() {
return item;
}
#endif
class const_iterator {
public:
Node *current;
const_iterator (Node *n) : current{n}
{
/* the body can remain blank, the initialization is carried
* the the constructor init list above
*/
}
/* copy assignment */
const_iterator operator= (const const_iterator& rhs) {
this->current = rhs.current;
return *this;
}
bool operator == (const const_iterator& rhs) const {
return this->current == rhs.current;
}
bool operator != (const const_iterator& rhs) const {
return this->current != rhs.current;
}
/* Update the current pointer to advance to the node
* with the next larger value
*/
const_iterator& operator++ () {
/*first step is to go left as far as possible(taken care of by begin())
once you go as left as possible, go right one step at a time*/
if(current->right != nullptr){
current = current->right;
//every step, go left again as far as possible
while(current->left != nullptr){
current = current->left;
}
}else{
bool upFromLeft = false;
bool upFromRight = false;
while(upFromLeft == false && upFromRight == false){
//if you have gone all the way up from the right
if(current->parent == nullptr){
upFromRight = true;
current = current->parent;
return *this;
}
//if you have gone all the way back up left
if(current->parent->left == current){
upFromLeft = true;
current = current->parent;
return *this;
}
current = current->parent;
}
}
return *this;
}
Z& operator *() const {
return current->data;
}
};
ADD these functions to your tree in order to use the begin() and end() with your iterator
const const_iterator begin() const {
if(rootPtr == nullptr){
return nullptr;
}
Node* temp = rootPtr;
while(temp->left != nullptr){
temp = temp->left;
}
return const_iterator(temp);
}
/* For the "end" marker
* we will use an iterator initialized to nil */
const const_iterator end() const {
return const_iterator(nullptr);
}
Here's an example of an in-order iterator I wrote in C++...
This iterator assumes that each node in your BST has a pointer to the parent node which is something I don't see in your node class. However, I am not sure its even possible to accomplish an inorder traversal without having a parent pointer.
In short, this example will work if you add a parent pointer to your nodes and update your parent pointers every time you do a node insertion or removal

c++ linking error for template, using only header files, why?

I know there are a lot of similar questions out there - believe me, I've read them - but I can't get this to work. Which is peculiar, because I resolved a similar struggle with a related program just the other day. I realize that the answer to my question quite likely is out there somewhere, but I've spent a good hour or two looking, without much success.
I am trying to build a linked list. The program consists of four files - header files for the linked list and the node, as well as an interace to the list, and the .cpp file containing the main method.
ListTester.cpp
#include "StdAfx.h"
#include "LinkedList.h"
#include <iostream>
#include <string>
using namespace std;
template <typename T>
void main() {
LinkedList<int> a;
a.addFirst(22);
a.addFirst(24);
a.addFirst(28);
LinkedList<int> b;
b = a;
b = b + a;
b += a;
cout<<b;
}
LinkedList.h
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include "Node.h"
#include "List.h"
#include <ostream>
template <typename T>
class LinkedList : public List {
private:
int n;
Node<T> *first;
Node<T> *last;
public:
LinkedList();
LinkedList(const LinkedList & ll);
~LinkedList();
int size();
void clear();
void addFirst(T data);
void addLast(T data);
T removeFirst();
T removeLast();
T getFirst();
T getLast();
Node<T>* getFirstNode() const;
void addAt(int pos, T data);
T removeAt(int pos);
T getAt(int pos);
LinkedList& operator=(const LinkedList<T> &right);
T operator[](int i);
LinkedList& operator+(const LinkedList<T> &right);
LinkedList& operator+=(const LinkedList<T> &right);
friend std::ostream& operator<<(std::ostream &os, const LinkedList<T> & ll);
};
template <typename T>
LinkedList<T>::LinkedList() {
this->n = 0;
this->first = 0;
this->last = 0;
}
template <typename T>
LinkedList<T>::LinkedList(const LinkedList & ll) {
this-> n = 0;
this-> first = 0;
this-> last = 0;
Node *temp = ll.first;
while(temp) {
addLast(temp->getData());
temp = temp->getNext();
}
}
template <typename T>
void LinkedList<T>::addFirst(T data) {
Node *p = new Node(data, first);
first = p;
if(!n)
last = p;
n++;
}
template <typename T>
void LinkedList<T>::addLast(T data) {
Node *p = new Node(data, 0);
if(!n)
first = last = p;
else {
last->next = p;
last = p;
}
n++;
}
template <typename T>
T LinkedList<T>::removeFirst() {
T a = 0;
if(!n)
throw "Can't retrieve element from empty list!";
a = first->getData();
Node *p = first->next;
delete first;
first = p;
n--;
return a;
}
template <typename T>
T LinkedList<T>::removeLast() {
T a = 0;
if(!n)
throw "Can't retrieve element from empty list!";
if(n == 1) {
a = last->getData();
delete first;
first = last = 0;
}
else {
a = last->getData();
Node *p = first;
while(p->next->next != 0)
p = p->next;
delete p->next;
p->next = 0;
last = p;
}
n--;
return a;
}
template <typename T>
T LinkedList<T>::getFirst() {
if(n < 1)
throw "Can't retrieve element from empty list!";
return first->getData();
}
template <typename T>
T LinkedList<T>::getLast() {
if(n < 1)
throw "Can't retrieve element from empty list!";
return last->getData();
}
template <typename T>
Node<T>* LinkedList<T>::getFirstNode() const {
return first;
}
template <typename T>
int LinkedList<T>::size() {
return n;
}
template <typename T>
T LinkedList<T>::getAt(int pos) {
if(pos >= n)
throw "Element index out of bounds!";
Node *temp = first;
while(pos > 0) {
temp = temp->next;
pos--;
}
return temp->getData();
}
template <typename T>
void LinkedList<T>::clear() {
Node *current = first;
while(current) {
Node *next = current->next;
delete current;
if(next)
current = next;
else
current = 0;
}
}
template <typename T>
void LinkedList<T>::addAt(int pos, T data) {
if(pos >= n)
throw "Element index out of bounds!";
if(pos == 0)
addFirst(data);
else {
Node *temp = first;
while(pos > 1) {
temp = temp->next;
pos--;
}
Node *p = new Node(data, temp->next);
temp-> next = p;
n++;
}
}
template <typename T>
T LinkedList<T>::removeAt(int pos) {
if(pos >= n)
throw "Element index out of bounds!";
if(pos == 0)
return removeFirst();
if(pos == n - 1)
return removeLast();
else {
Node *p = first;
while(pos > 1) {
p = p->next;
pos--;
}
T a = p->next->getData();
Node *temp = p->next;
p->next = p->next->next;
delete temp;
n--;
return a;
}
}
template <typename T>
LinkedList<T>::~LinkedList() {
clear();
}
template <typename T>
LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T> &right) {
if(this != &right) {
n = 0;
first = 0;
last = 0;
Node *temp = right.first;
while(temp) {
addLast(temp->getData());
temp = temp->getNext();
}
}
return *this;
}
template <typename T>
T LinkedList<T>::operator[](int i) {
return getAt(i);
}
template <typename T>
LinkedList<T>& LinkedList<T>::operator+(const LinkedList<T> &right) {
Node *temp = right.first;
while(temp) {
addLast(temp->getData());
temp = temp->getNext();
}
return *this;
}
template <typename T>
LinkedList<T>& LinkedList<T>::operator+=(const LinkedList<T> &right) {
Node *temp = right.first;
while(temp) {
addLast(temp->getData());
temp = temp->getNext();
}
return *this;
}
template <typename T>
std::ostream& operator<<(std::ostream &os, const LinkedList<T> &ll) {
Node *temp = ll.getFirstNode();
while(temp) {
os<<temp->getData()<<std::endl;
temp = temp->getNext();
}
return os;
}
#endif
Node.h
#ifndef NODE_H
#define NODE_H
template <typename T>
class Node {
private:
T data;
public:
Node<T>* next;
T getData();
Node<T>* getNext();
Node(T data, Node<T>* next);
Node(const Node & n);
};
template <typename T>
T Node<T>::getData() {
return data;
}
template <typename T>
Node<T>* Node<T>::getNext() {
return next;
}
template <typename T>
Node<T>::Node(T data, Node<T>* next) {
this->data = data;
this->next = next;
}
template <typename T>
Node<T>::Node(const Node & n) {
data = n.data;
next = n.next;
}
#endif
List.h
#ifndef LIST_H
#define LIST_H
class List
{
public:
virtual void addFirst(int data) = 0;
virtual void addAt(int pos, int data) = 0;
virtual void addLast(int data) = 0;
virtual int getFirst()= 0;
virtual int getAt(int pos) = 0;
virtual int getLast()= 0;
virtual int removeFirst()= 0;
virtual int removeAt(int pos) = 0;
virtual int removeLast()= 0;
virtual int size() = 0;
virtual void clear() = 0;
virtual ~List() {};
};
#endif
For this, I get LNK2019 and LNK1120 linking errors. I know I used to get this when implementing a Queue in separated .h and .cpp files. But worked around it by doing everything in the header. I also know that this can happen when not implementing a named method, but I can't find any of those here. So what's causing this? I wish the compiler / IDE could point me to the possible cause of the error. But then again, if it was an easy task to find the faulty line, I assume it would already do this. VS 2012 btw.
You made main a function template. Not only does this not make sense (there is no mention of the template parameter inside), it's also never instantiated (and even if it was, it probably wouldn't resolve to the correct main that a program needs as a start point).
Furthermore, it should be int main rather than void main.
// template <typename T>
void main() {
LinkedList<int> a;
a.addFirst(22);
a.addFirst(24);
a.addFirst(28);
LinkedList<int> b;
b = a;
b = b + a;
b += a;
cout<<b;
}
You need a main function, not a main function template. That's probably the source of your linker error: no function called "main".
The reason this won't work is primarily because class templates and function templates are never expanded to real code unless they're used. Since main is the entrypoint to your program, you never call main from anywhere and thus no code for main is ever generated.
Furthermore due to the name mangling that C++ compilers do to functions (to handle overloading, templates, namespaces etc) the symbol that will be generated in the resulting assembly for this main template probably won't be the right one. If it's looking for a symbol 'main' and it sees
$__T_float_main_blah_blah_blah
then you won't link anyways. Long story short: main is a function, not a function template.