I'm struggling with Implementing STL Double LinkedList. I'm almost a newbie with c++ and OOP programming, I've almost good knowledge of C language but all these new concepts are difficult to grasp and implement with data structure. I'm trying to make a good generic ADT following the STL style with iterator pattern and template.
There are no Syntax error, instead, there is a big logic problem with element insertion(pushFront function) that insert only the last element(check main function), I tried to debug but still can't find the problem. Hope that someone can help me :-)
These are my code snippet
Node class:
//Forward declaration
template<class T>
class LinkedList;
//Node should be structure?
template<class T>
class Node
{
friend class LinkedList<T>;
public:
Node(): pPrev_(nullptr), pNext_(nullptr) {}
Node(const T& value): data_(value), pPrev_(nullptr), pNext_(nullptr) {}
/*
* Implementing double linked list node
* data_: node's data of type T
* pNext_: pointer to the next node
* pPrev_: pointer to the previous node
*/
// if I put Private there some errors with private stuff, I have declared also LInkedList as friend
T data_;
Node<T>* pPrev_;
Node<T>* pNext_;
};
Iterator Class:
template<class T>
class ListIterator
{
// Declaring LinkedList friend class, now
//LinkedList can access to all data in this class
friend class LinkedList<T>;
public:
//Constructors
ListIterator();
ListIterator(Node<T>* node);
//Destructor
~ListIterator();
// Assignement Overload
//ListIterator<T> operator=(const)
//Deferencing Overload
T operator*();
//Prefix Overload
ListIterator<T> operator++();
ListIterator<T> operator--();
//Postfix Overload
ListIterator<T> operator++(int);
ListIterator<T> operator--(int);
//Relational Overload
bool operator==(const ListIterator<T>& Node);
bool operator!=( const ListIterator<T>& Node);
private:
// Actual node holden by iterator
Node<T>* curNode_;
};
/*
LIST_ITERATOR IMPLEMETATION
*/
template <class T>
ListIterator<T>::ListIterator(): curNode_(nullptr){}
template <class T>
ListIterator<T>::ListIterator(Node<T>* node): curNode_(node) {}
//Destructor
template <class T>
ListIterator<T>::~ListIterator() {}
//Deferencing Overload
template <class T>
T ListIterator<T>::operator *()
{
//Return the VALUE of the current node holden by iterator
return this->curNode_->data_;
}
//Prefix Overload
template <class T>
ListIterator<T> ListIterator<T>::operator ++()
{
/*
* Check if the next node is a valid node, then
* the current node will be the next node
* Return the value of the current node
*/
if (this->curNode_->pNext_ != nullptr)
this->curNode_ =this->curNode_->pNext_; //Like it++, jump to the next node
return *this;
}
template <class T>
ListIterator<T> ListIterator<T>::operator --()
{
/*
* Check if the previous node is a valid node, then
* the current node will be the previous node
* Return the value of the current node
*/
if( this->curNode_->pPrev_ != nullptr)
this->curNode_ = this->curNode_->pPrev;
return *this; //?? why return this
}
//Postfix Overload
template <class T>
ListIterator<T> ListIterator<T>::operator ++(int)
{
ListIterator<T> temp= *this;
++(*this);
return temp;
}
template <class T>
ListIterator<T> ListIterator<T>::operator --(int)
{
ListIterator<T> temp= *this;
--(*this);
return temp;
}
// Inequalities Overload
template <class T>
bool ListIterator<T>::operator==(const ListIterator<T>& node)
{
/*
* Check if the address of the current node is equal to the address of node param
*/
return( this->curNode_== node.curNode_);
}
template <class T>
bool ListIterator<T>::operator!=(const ListIterator<T>& node)
{
return !((*this) == node);
}
LinkedList Class:
template<class T>
class LinkedList
{
public:
typedef ListIterator<T> iterator;
//Constructors
LinkedList();
LinkedList(const LinkedList<T>& copyList);
//Destructor
~LinkedList();
//List Status Methods
bool isEmpty();
unsigned int getSize();
iterator begin();
iterator end();
//Should parameters be constant and passed by reference &? let's check with tester if there are some troubles
//Insert Methods
void pushFront(const T value);
void pushBack(const T value);
void insertAt(const T value,iterator& atPos);
//Remove Methods
void popFront();
void popBack();
void removeAt(iterator& pos);
void clear();
/** Addtional methods
*
* sort
* min,max,
* clear,
* overload <<
* print
*/
private:
/*
* Keeping a pointer to head and tail of the list;
* Size_: number of list's element
*/
Node<T>* Head_;
Node<T>* Tail_;
unsigned int Size_;
};
// LIST IMPLEMENTATION
// Constructors
template < class T>
LinkedList<T>::LinkedList()
{
/*
* Create a new empty node, head and tail are/share the same node at this step.
* Assign to head's pointer to next node NULL
* Assign to tail's pointer to previous node NULL
*/
this->Head_=this->Tail_= new Node<T>;
this->Head_->pNext_= nullptr;
this->Tail_->pPrev_= nullptr;
this->Size_=0;
}
// WIP TO CHECK
template <class T>
LinkedList<T>::LinkedList(const LinkedList<T>& list){
this->Head_=this->Tail_= new Node<T>;
this->Head_->pNext_= nullptr;
this->Tail_->pPrev_= nullptr;
this->Size_=0;
// create iterator to loop inside the container
for(iterator it= list.begin ; it != list.end(); it++)
this->pushBack(*it);
}
//Destructor
template <class T>
LinkedList<T>::~LinkedList()
{
this->clear(); //delete all nodes
delete this->Tail_;
}
//Begin & end()
template <class T>
ListIterator<T> LinkedList<T>::begin()
{
iterator it= this->Head_;
return it;
}
template <class T>
ListIterator<T> LinkedList<T>::end()
{
iterator it= this->Tail_;
return it;
}
//Clear
template< class T>
void LinkedList<T>::clear()
{
iterator it= this->begin();
while(it != this->end())
this->removeAt(it);
}
These are the methods that gives me error:
//Insert At
template <class T>
void LinkedList<T>::insertAt(const T value, iterator& atPos)
{
Node<T>* newNode= new Node<T>;
newNode->data_= value;
//Add links
if( atPos == this->begin())
{
newNode->pNext_=this->Head_;
this->Head_=newNode;
}
else if ( atPos == this->end())
//Still to implement
this->Tail_= newNode;
else
{
newNode->pNext_ = atPos.curNode_;
atPos.curNode_->pPrev_ = newNode;
atPos.curNode_->pPrev_->pNext_ = newNode;
newNode->pPrev_=atPos.curNode_->pPrev_;
}
atPos.curNode_= newNode;
this->Size_++;
}
template <class T>
void LinkedList<T>::pushFront(const T value)
{
iterator it= this->begin();
this->insertAt(value, it);
}
And here some lines to test the ADT:
#include <iostream>
#include <stdlib.h>
#include <string>
#include "LinkedList.h"
using namespace std;
int main() {
Node<int> nd(4);
ListIterator<int> it;
LinkedList<int> lst;
for(int i=0; i < 25;i++)
lst.pushFront(i);
for(it=lst.begin(); it != lst.end();it++)
{
cout << *it << endl;
system("Pause");
}
cout << "iia";
system("Pause");
return 0;
}
There are no errors in your output:
24
Press any key to continue . . .
23
Press any key to continue . . .
22
Press any key to continue . . .
...
Press any key to continue . . .
0
Press any key to continue . . .
iiaPress any key to continue . . .
P.S. don't use this where you can avoid it. Code will be easier for reading.
Related
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;
}
I'm trying to work on an assignment where the professor has requested that the iterator for a Linked List has to be a separate header file.
However, all implementations I've seen of Iterators I've seen have the definition of the class inside of the bag/list class. So I have no idea how to create an iterator within the bag like
dlist<int>::iterator it1
without defining it inside the list.
For reference, here are my list, node, and iterator classes as is:
dnode.h
template <class T>
class dnode{
public:
dnode(){
linknext = NULL;
prevlink = NULL;
}
void set_data(T item){data_value = item;}
void set_next(dnode<T> *link){linknext = link;}
void set_prev(dnode<T> *link){prevlink = link;}
T data()const{return data_value;}
dnode *next(){return linknext;}
dnode *prev(){return prevlink;}
private:
dnode *linknext;
dnode *prevlink;
T data_value;
};
dlist.h
#include "dnode.h"
#include "iterator.h"
template <class T>
class dlist{
public:
dlist(){head = tail = NULL;}
void rear_insert(T data);
void front_insert(T data);
void front_remove();
void rear_remove();
void reverse_show();
void show();
iterator<T> begin(){return iterator<T>(head);}
iterator<T> end(){return iterator<T>(tail);}
iterator<T> r_begin(){return iterator<T>(tail);}
iterator<T> r_end(){return iterator<T>(head);}
void insert_after(iterator<T>& current,T item){
dnode<T>* tmp;
tmp = new dnode<T>;
current.get_dnode()->next()->set_prev(tmp);
tmp->set_data(item);
tmp->set_next(current.get_dnode()->next());
tmp->set_prev(current.get_dnode());
current.get_dnode()->set_next(tmp);
}
void insert_before(iterator<T>& current,T item){
dnode<T>* tmp;
tmp = new dnode<T>;
current.get_dnode()->prev()->set_next(tmp);
tmp->set_data(item);
tmp->set_next(current.get_dnode());
tmp->set_prev(current.get_dnode()->prev());
current.get_dnode()->set_prev(tmp);
}
friend class iterator<T>;
private:
dnode<T> *head;
dnode<T> *tail;
};
iterator.h
template <class T>
class iterator
{
public:
iterator(dnode<T> *first = NULL){current = first;}
dnode<T>* get_dnode(){return current;}
T& operator *()const{return current->data();}
iterator& operator ++(){
current = current->next();
return *this;
}
iterator& operator ++(int){
iterator original(current);
current = current->next();
return original;
}
iterator& operator --(){
current = current->prev();
return *this;
}
iterator& operator --(int){
iterator original(current);
current = current->prev();
return original;
}
bool operator ==(const iterator something)const{ return current == something.current;}
bool operator !=(const iterator something)const{ return current == something.current;}
private:
dnode<T> *current;
};
Thanks for any assistance.
You can declare the iterator and node types within the list class but define them elsewhere. The syntax you need is of the form as follows:
template <class T>
class list {
public:
class iterator;
struct node;
node* head;
iterator begin()
{
return head;
}
iterator end()
{
return head->prev;
}
};
template <class T>
class list<T>::iterator {
node* pos;
public:
iterator(node* p) : pos (p) { }
// ...
};
template <class T>
struct list<T>::node {
node* next;
node* prev;
// ...
};
void f()
{
list<int> l;
list<int>::iterator i = l.begin();
list<int>::node n;
}
When inside the definition of list, node or iterator you should no longer need the list:: prefix. Outside (which includes return types on functions defined outside those classes) you do need the list:: prefix.
In this form your include structure will be the reverse of what you have above where list.h does not need to include node.h or iterator.h but both of those files will include list.h. You might want to include node.h and iterator.h at the end of list.h so that users of your class can get all the definitions by including list.h.
i am writing this code a generic list , now in this generic list i did a class for iterator that helds two parameters : one is a pointer to the list he points to .
and the other one points to the element in the list he points to ..
now i need to write an insert function that inserts a new element to a given list , with the following rules :: where i insert a new node to the list, and in this function if the iterator poiints to the end of the list the we add the new node to the end of the list else we insert the node one place before the node that the iterator currently points to , and if the iteratot points to a different node then thats an error .
now i want the iterator to be defoult so in case in the tests someone called the function with one parameter i want the iterator to be equal to the end element of the list.
the function end i wrote it inside of the list.
now in the insert function i did that but i get this error :
cannot call member function "List::iterator List::end()"without object
.
#include <iostream>
#include <assert.h>
#include "Exceptions.h"
template <class T>
class List {
public:
List();
List(const List&);
~List();
List<T>& operator=(const List& list);
template <class E>
class ListNode {
private:
ListNode(const E& t, ListNode<E> *next): data(new E(t)), next(next){}
~ListNode(){delete data;}
E* data;
ListNode<E> *next;
public:
friend class List<E>;
friend class Iterator;
E getData() const{
return *(this->data);
}
ListNode<E>* getNext() const{
return this->next;
}
};
class Iterator {
const List<T>* list;
int index;
ListNode<T>* current;
Iterator(const List<T>* list, int index): list(list),
index(index),current(NULL){
int cnt=index;
while (cnt > 0) {
current = current->next;
cnt--;
}
}
friend class List<T>;
friend class ListNode<T>;
public:
// more functions for iterator
};
Iterator begin() const ;
Iterator end() const;
void insert(const T& data, Iterator iterator=end());//here i get the error
void remove(Iterator iterator);
class Predicate{
private:
T target;
public:
Predicate(T i) : target(i) {}
bool operator()(const T& i) const {
return i == target;
}
};
Iterator find(const Predicate& predicate);
class Compare{
private:
T target;
public:
Compare(T i) : target(i) {}
bool operator()(const T& i) const {
return i < target;
}
};
bool empty() const;
int compareLinkedList(ListNode<T> *node1, ListNode<T> *node2);
private:
ListNode<T> *head;
ListNode<T> *tail;
int size;
};
any help would be amazing ! cause i don't know why such a mistake apears .
//insert function just in case :
template <typename T>
void List<T>::insert(const T& data, Iterator iterator=end()){
if(iterator.list!=this){
throw mtm::ListExceptions::ElementNotFound();
return;
}
ListNode<T> *newNode = new ListNode<T>(data, iterator.current);
if(iterator.index==size){
if (head == NULL) {
head = newNode;
tail=newNode;
}else{
Iterator temp(this,size-1);
temp.current->next=newNode;
}
//newNode->next=this->end().current;
}
else {
if (head == NULL) {
head = newNode;
tail=newNode;
}
else {
Iterator temp1(this,iterator.index-1);
temp1.current->next=newNode;
newNode->next=iterator.current->next;
}
}
size++;
}
void insert(const T& data, Iterator iterator=end());
This is the offending line. A default argument cannot be the result of a member function call. The right tool to achieve what you want is overloading.
void insert(const T& data, Iterator iterator);
void insert(const T& data) { insert(data, end()); }
Here we still defer to the insert function you implemented, but we call end from within the overloads body, where it's allowed.
Don't worry about the indirect call. This is a very small function that's defined inside the class declaration itself. Any decent compiler will inline it completely.
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()).
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