I'm trying to implement a linked list class in C++ and I got problem. I have the += operator who adds new node.
the linked list class interface:
template <typename Type>
class LinkedList {
public:
LinkedList<Type>* head;
// linked list stracture
Type data;
LinkedList<Type>* next;
// others ....
size_t length;
public:
LinkedList();
~LinkedList();
void initializeHead(LinkedList<Type>* headPtr);
size_t size() const;
LinkedList& operator+=(const Type& add);
void operator-=(const Type& remove);
LinkedList<Type>& operator[] (const size_t index) const;
bool operator== (const LinkedList<Type> &versus) const;
friend ostream& operator<< (ostream& out,LinkedList& obj);
};
and here i have the += overload implement:
template <typename Type> LinkedList<Type>& LinkedList<Type>::operator +=(const Type& add) {
// head ptr - :)
LinkedList<Type>* p = head->next;
// go to the end
while(p) p = p->next;
// now on end - create new..!!!
try {
p = new LinkedList<Type>;
} catch (bad_alloc& e) {
cout << "There\'s an allocation error....";
} catch (...) {
cout << "An unknown error.." << endl;
}// fill and done
p->data = add;
p->next = NULL;
// increment length .........
++head->length;
// done ............
return *p;
}
Additionally , I have "array" access overload method:
template <typename Type> LinkedList<Type>& LinkedList<Type>::operator [](const size_t index) const {
if(index < 0 || index >= length) // invaild argument
throw exception();
// continue
LinkedList<Type>* p = head;
for(size_t i = 0; i < index; ++i) p = p->next; // we are at what we want
return *p;
}
All works correctly - I checked on the dibugger,
the problem is - += doesn't save the new node in "head->next", for some reason, after finish += method, head->next equal to null.
Do someone know why the new allocation don't link to head->next?
Thanks a lot!!
after while(p) p = p->next; p is NULL
and next you do p = new LinkedList<Type>; but you don't link the p into the head.
Instead of:
// go to the end
while(p) p = p->next;
You need:
head->next = p;
As the other answers say, you go beyond the list when you try to add. Try something like this:
template <typename Type> LinkedList<Type>& LinkedList<Type>::operator +=(const Type& add)
{
LinkedList<Type> *last;
// Find the last node in the list
for (last = head; last != 0 && last->next != 0; last = last->next)
{
}
// `last` now points to the last node in the list, or is zero
// If zero (i.e. NULL) then list is empty
if (last == 0)
{
head = new LinkedList<Type>;
head->next = 0;
head->data = add;
head->length = 0;
}
else
{
last->next = new LinkedList<Type>;
last->next->next = 0;
last->next->data = add;
}
// We can safely use `head` as we are sure it won't be zero
head->length++;
// Return the added node
return (last != 0 ? *last->next : *head);
}
You can also use temporary variable to store last node and then the last node will point to new node.
This is sample code. You need to take care of some situations like adding first node etc.
LinkedList<Type>* temp = NULL;
while(p)
{
temp = p;
p = p->next;
}
try
{
p = new LinkedList<Type>;
temp->next = p;
}
Related
There is an issue with my code. I need to write a program that creates a linked list and performs insertion, deleting from the beginning, deleting from the end, and printing. Everything in the program works fine, but the delete the first node function. It throws an error in the printing function (posted a picture of the error below). Does anyone know what seems to be the problem? The function that deletes the last node works and prints perfectly.
LINKED LIST PROGRAM:
struct Node {
int data;
Node* next;
};
void insert(Node** head,int n) //insertion method
{
Node* newNode = new Node;
newNode->data = n;
newNode->next = (*head);
(*head) = newNode;
}
Node* deleteFront(struct Node* head)//deleting first node in the list
{
if (head == NULL)
return NULL;
else
{
Node* t = head;
head = head->next;
free(t);
t = NULL;
}
return head;
}
Node* deleteEnd(struct Node* head)//deleting last node in the list
{
if (head == NULL)
return NULL;
else if (head->next == NULL) {
free(head);
head = NULL;
}
else {
Node* prev = head;
Node* prev2 = head;
while (prev->next != NULL)
{
prev2 = prev;
prev = prev->next;
}
prev2->next = NULL;
free(prev);
prev = NULL;
}
return head;
}
void printLL(Node* h)
{
while (h != NULL)
{
cout << h->data << " ";
h = h->next;
}
cout << endl;
}
int main()
{
cout << "Linked list question 2: " << endl;
//linked list question 2
Node* n = NULL;
insert(&n, 60);
insert(&n, 40);
insert(&n, 20);
printLL(n);
deleteFront(n);
cout << "after deleting first node: ";
printLL(n);
deleteEnd(n);
cout << "after deleting last element: ";
printLL(n);
}
A picture of the error:
error
output
Take it easy. I read your code and there are no errors in logic. However, there are some mistakes in the selection of parameters. It is not necessary to use ** in the insert. Using * can meet the requirements, and use & to achieve assignment to the linked list. The same is true for deleteFront and deleteEnd. I modified your code and now the program can run normally, hope it helps.
#include<iostream>
using namespace std;
struct Node {
int data;
Node* next;
};
void insert(Node*& head, int n) //insertion method
{
Node* newNode = new Node;
newNode->data = n;
newNode->next = head;
head = newNode;
}
Node* deleteFront(struct Node*& head)//deleting first node in the list
{
if (head == NULL)
return NULL;
else
{
Node* t = head;
head = head->next;
free(t);
t = NULL;
}
return head;
}
Node* deleteEnd(struct Node*& head)//deleting last node in the list
{
if (head == NULL)
return NULL;
else if (head->next == NULL) {
free(head);
head = NULL;
}
else {
Node* prev = head;
Node* prev2 = head;
while (prev->next != NULL)
{
prev2 = prev;
prev = prev->next;
}
prev2->next = NULL;
free(prev);
prev = NULL;
}
return head;
}
void printLL(Node* h)
{
while (h != NULL)
{
cout << h->data << " ";
h = h->next;
}
cout << endl;
}
int main()
{
cout << "Linked list question 2: " << endl;
//linked list question 2
Node* n = NULL;
insert(n, 60);
insert(n, 40);
insert(n, 20);
printLL(n);
deleteFront(n);
cout << "after deleting first node: ";
printLL(n);
deleteEnd(n);
cout << "after deleting last element: ";
printLL(n);
}
Since you're returning head in deleteFront(n) and deleteLast(n), however you're not updating head in main(). That's why its n is pointing to some garbage memory. Update your main() by storing head in n variable.
int main()
{
cout << "Linked list question 2: " << endl;
//linked list question 2
Node* n = NULL;
insert(&n, 60);
insert(&n, 40);
insert(&n, 20);
printLL(n);
n = deleteFront(n);
cout << "after deleting first node: ";
printLL(n);
n = deleteEnd(n);
cout << "after deleting last element: ";
printLL(n);
}
The bugs in your code have been mentioned in other answers and there were proposals to fix.
I would like to add an additional observation regarding your design of the Linked List. In standard implementations, Node is not visible to the outside world. The Node is not the LinkedList. The linked list contains Nodes. So, you would create a class List and it would contain the definition of a Node and a head pointer to the first node instance.
Then you would add all you functions as methods to the outer class List. These methods would work with the internal Node-chain. According to object oriented model you would encapsulate the interna of the methods and expose only what is needed to the outside world.
What you should also note is that your list is a forward list only. It has only one link to the next element. This makes some operations difficult, because you may need to always go from the beginning the list through the element what you what operate on. See your function delete_end. Here you even need to remember the previous element.
In double linked list, you could simply access also the previous element.
Therefore, if you check the CPP reference for a std::forward_list, you will find some maybe strange sounding functions like insert_after or erase_after or an iterator before_begin. This is all the result of having just forward references. A function like delete_last which would be pop_back in CPP language, is even not existing.
Therefore you maybe need to confirm, if you should implement a singly linked list or maybe a double linked list.
To make this more visible for you, I created some complete example code for a singly linked list for you.
Here I added also simple iterator functionality, which allows to use the class in a convenient way, e.g. with range based for loops or std::algorithms.
You may take this code to get some ideas for your own implementation.
#include <iostream>
#include <iterator>
#include <initializer_list>
#include <algorithm>
// Very simple implementation of a forward list
class SinglyLinkedList {
// The node
struct Node {
int data{}; // Data. Would normally be a templated argument
Node* next{}; // And the pointer to the next node
Node(int i, Node* n=nullptr) : data(i), next(n) {}; // Simple constructor to set a value and next pointer
};
Node* head{}; // This is the start of the list
// It would be advisable to have a tail pointer. We use the more inefficient approach here
Node* getLast() { Node* n{ head }; while (n and n->next) n = n->next; return n; }
public:
// Constructor / Destructor --------------------------------------------------------------------------------------------------------
~SinglyLinkedList() { clear(); }
// Default constuctor
SinglyLinkedList() {} // Default
// From an initialization list
SinglyLinkedList(const std::initializer_list<int>& il) { clear(); for (const int i : il) push_back(i); } // From initializer list
// Copy constructor
SinglyLinkedList(const SinglyLinkedList& other) { clear(); for (const int i : other) push_back(i); }
// Move constructor. Will steal the elements from the other
SinglyLinkedList(SinglyLinkedList&& other) noexcept { head = other.head; other.head = nullptr; }
// Assignment operator
SinglyLinkedList& operator = (const SinglyLinkedList& other) { clear(); for (const int i : other) push_back(i); }
// Move assignment operator
SinglyLinkedList& operator = (SinglyLinkedList&& other) { head = other.head; other.head = nullptr; }
// Housekeeping --------------------------------------------------------------------------------------------------------------
void clear() { Node* tmp{ head }; while (tmp) { Node* toDelete{ tmp }; tmp = tmp->next; delete toDelete; } head = nullptr; }
int empty() { return head == nullptr; }
int size() { int k{}; Node* n{ head }; while (n) { ++k; n = n->next; } return k; }
// Modify content --------------------------------------------------------------------------------------------------------------
void push_front(int i) { Node* n = new Node(i); n->next = head; head = n; };
void push_back(int i) { Node* n = new Node(i); Node* l = getLast();if (l) l->next = n; else head = n; }
void pop_front() { if (head) { Node* tmp = head->next; delete head; head = tmp; } }
void pop_back() { // This is a little bit more difficult in a singly linked list
if (head) {
Node* n{ head }, *previous{};
while (n and n->next) {
previous = n;
n = n->next;
}
delete n;
if (previous)
previous->next = nullptr;
else
head->next = nullptr;
}
}
// Access elements --------------------------------------------------------------------------------
int front() { return head ? head->data : 0; };
int back() { Node* n = getLast(); return n ? n->data: 0; }
// Add iterator properties to class ---------------------------------------------------------------
struct iterator { // Local class for iterator
Node* iter{}; // Iterator is basically a pointer to the node
// Define alias names necessary for the iterator functionality
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = int;
using pointer = int*;
using reference = int&;
// Constructor
iterator() {}
iterator(Node* n) : iter(n) {}
// Dereferencing
reference operator *() const { return iter->data; }
pointer operator ->() const { return &iter->data; }
// Aithmetic operations
iterator& operator ++() { if (iter) iter = iter->next; return *this; }
iterator operator ++(int) { iterator temp{ *this }; ++* this; return temp; }
iterator operator +(const difference_type& n) const { iterator temp{ *this }; difference_type k{ n }; while (k--)++temp; return temp; }
iterator& operator +=(const difference_type& n) { difference_type k{ n }; while (k--)++* this; return *this; };
// Comparison
bool operator != (const iterator& other) const { return iter != other.iter; }
bool operator == (const iterator& other) const { return iter == other.iter; }
bool operator < (const iterator& other) const { return iter < other.iter; }
bool operator > (const iterator& other) const { return iter > other.iter; }
bool operator <= (const iterator& other) const { return iter <= other.iter; }
bool operator >= (const iterator& other) const { return iter >= other.iter; }
// Difference. Also complicated, because no random access
difference_type operator-(const iterator& other) const {
difference_type result{};
Node* n{ iter };
while (n and n != other.iter) {
++result;
n = n->next;
}
return result;
}
};
// Begin and end function to initialize an iterator
iterator begin() const { return iterator(head); }
iterator end() const { return iterator(); }
// Functions typcical for forward lists ----------------------------------------------------------------------
// Easy, becuase we can operate form the current iterator and do not need the "previous" element
iterator insertAfter(iterator& pos, const int i) {
iterator result{};
if (pos.iter and pos.iter->next) {
Node* n = new Node(i, pos.iter->next);
pos.iter->next = n;
result = n;
}
return result;
}
iterator eraseAfter(iterator& pos) {
iterator result{};
if (pos.iter and pos.iter->next) {
Node* tmp = pos.iter->next->next;
delete pos.iter->next;
pos.iter->next = tmp;
result = pos.iter->next;
}
return result;
}
};
// Test/Driver Code
int main() {
// Example for initilizer list
SinglyLinkedList sllbase{5,6,7,8,9,10,11,12,13,14,15};
// Show move constructor
SinglyLinkedList sll(std::move(sllbase));
// Add some values in the front
sll.push_front(4);
sll.push_front(3);
sll.push_front(2);
sll.push_front(1);
// Delete 1st element (Number 1)
sll.pop_front();
// Delete last element
sll.pop_back();
// Use a std::algorithm on our custom linked list. Works because we have an interator
SinglyLinkedList::iterator iter = std::find(sll.begin(), sll.end(), 8);
// Now add an element after 8
iter = sll.insertAfter(iter,88);
// End delete the 9
iter = sll.eraseAfter(iter);
// Use range based for loop. Works because, we have iterators
for (int i : sll)
std::cout << i << ' ';
}
I have written a linked list(which is aimed for the data type int) implementation.
Seems to be working fine except when I try to sort the list in such a way that all the odd
elements should come after all the even elements with the original order of the even and odd numbers preserved.
Upon debugging in MS Visual Studio, I found out that in the oddevenSort() function, the for loop seems to be going on infinitely...as if somehow the tail->next was not being updated to nullptr.
I can't seem to grasp where the error lies in my logic.
#include<iostream>
template<class T>
class SLL_Node
{
public:
T info;
SLL_Node* next;
SLL_Node();
SLL_Node(T el, SLL_Node<T>* n = nullptr);
};
template<class T>
class SLL
{
private:
SLL_Node<T>* head, * tail;
size_t size;
public:
SLL();
~SLL();
bool isEmpty() const;
size_t get_size() const;
void add_to_head(T el);
void add_to_tail(T el);
void delete_at(size_t); //delete at a certain index. Index starting from 1. Throws an error //message if index out of bounds or list empty.
void display()const; //the logic is for mostly primitive data types and not user defined data //types (including classes)
void oddevenSort();
};
template<class T>
bool SLL<T>::isEmpty() const
{
if (tail == nullptr)
return true;
else
return false;
}
template<class T>
SLL_Node<T>::SLL_Node() : next{ nullptr }
{}
template<class T>
SLL_Node<T>::SLL_Node(T el, SLL_Node<T>* n) : info{ el }, next{ n }
{}
template<class T>
SLL<T>::SLL()
{
size = 0;
head = tail = nullptr;
}
template<class T>
void SLL<T>::add_to_tail(T el)
{
++size;
if (!isEmpty())
{
tail->next = new SLL_Node<T>(el);
tail = tail->next;
}
else
head = tail = new SLL_Node<T>(el);
}
template<class T>
void SLL<T>::add_to_head(T el)
{
head = new SLL_Node<T>(el, head);
if (tail == nullptr) //if empty
{
tail = head;
}
++size;
}
template<class T>
void SLL<T>::display()const
{
std::cout << '\n';
for (SLL_Node<T>* tmp{ head }; tmp != nullptr; tmp = tmp->next)
{
std::cout << tmp->info << "->";
}
std::cout << "NULL\n";
}
template<class T>
void SLL<T>::delete_at(size_t index)
{
if (index >= 1 && index <= size) //bound checking
{
if (!isEmpty()) //we dont need is empty since size takes care of that but still adding it for clarity
{
if (head == tail && index == 1) //if list only has one node and we delete head node
{
delete head;
head = tail = nullptr;
}
//otherwise if list more than one node
else if (index == 1) //if deleting head node
{
SLL_Node<T>* tmp{ head };
head = head->next;
delete tmp;
tmp = nullptr;
}
else //deleting other nodes
{
SLL_Node<T>* tmp{ head->next }, * pred{ head };
for (size_t i{ 2 }; i < index; ++i)
{
tmp = tmp->next;
pred = pred->next;
}
pred->next = tmp->next;
if (tmp == tail)
{
tail = pred;
}
delete tmp;
tmp = nullptr;
}
}
}
else
{
std::cout<<"\nError! Either the list is empty or the index entered is out of bounds!\n";
}
}
template<class T>
void SLL<T>::oddevenSort()
{
SLL_Node<T>* t=head;
size_t count{1};
for (; t != nullptr; t = t->next)
{
if (((t->info) % 2) != 0)
{
add_to_tail(t->info);
delete_at(count);
}
++count;
}
}
main:
int main()
{
SLL<int> a;
a.add_to_head(1);
a.add_to_head(2);
a.add_to_tail(3);
a.add_to_tail(4);
a.add_to_head(6);
a.add_to_tail(7);
a.add_to_head(5);
a.display();
//a.oddevenSort();
a.display();
return 0;
}
Consider an example input for oddevenSort a(1)->b(2) ->c(3)->null
on 1st iteration t is pointing to a(1) new node is created with
data 1 which is appended at the end of list like
b(2)->c(3)->d(1)->null.
On 2nd iteration t will point to node b(2) and no changes done
on list.
On 3rd iteration t will point to node c(3) new node is created
with data 3 which is appended at the end of list like
b(2)->d(1)->e(3)->null.
on 4th iteration t will point to d(1) which creates new node at the end of list. Iteration goes on and on recursively without breaking the loop.
Every time you need not to delete and create the new node. You can segregate even and odd nodes and make final list.
Here is the updated snippet
template<class T>
void SLL<T>::oddevenSort()
{
SLL_Node <T>tempOddHeader;
SLL_Node <T> *tempOddPtr = &tempOddHeader;
SLL_Node <T> tempEvenHeader;
SLL_Node <T> *tempEvenPtr = &tempEvenHeader;
SLL_Node<T>* t = head;
tempOddHeader.next = nullptr;
tempEvenHeader.next = nullptr;
while(t)
{
if (((t->info) % 2) != 0) {
//append to the odd list
tempOddPtr->next = t;
tempOddPtr = tempOddPtr->next;
t = t->next;
tempOddPtr->next = nullptr;
}
else {
//append to the even list
tempEvenPtr->next = t;
tempEvenPtr = tempEvenPtr->next;
t = t->next;
tempEvenPtr->next = nullptr;
}
}
tempEvenPtr->next = tempOddHeader.next;
head = tempEvenHeader.next;
tail = tempOddPtr;
}
I have this code from an old exam, which I want fix from its faults. Everytime I call insertlast/insertfirst I allocate new memory for my list which I can't seem to free. I have run it with valgrind and gets a new leak everytime i call insertfirst/insertlast. Valgrind also complains on my loop where I try to free the memory. I get something like this:
Invalid free() / delete / delete[] / realloc()
==4548== at 0x4C2C2BC: operator delete(void*)(in/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4548== by 0x4007D6: main (code6.cpp:67)
==4548== Address 0xffefffea0 is on thread 1's stack
Here's the code:
#include <iostream>
using namespace std;
template <class T>
struct Node {
Node() : data(T()), next(nullptr) {}
Node(T d, Node * p) : data(d), next(p) {}
T data;
Node<T> * next;
};
template <class T>
void insertlast (Node<T> * p, T data) {
if (p == nullptr) {
p = new Node<T>(data, nullptr);
} else {
while (p -> next != nullptr) {
p = p -> next;
}
p -> next = new Node<T>(data, nullptr);
}
}
template <class T>
void insertfirst (Node<T> * & p, const T & data) {
Node<T> * tmp = new Node<T>(data, p);
p = tmp;
}
template <class T>
void printNode(Node<T> *& node) {
cout << node->data << " -> ";
while (node->next != nullptr) {
node = node->next;
cout << node->data << " -> ";
}
cout << endl;
}
template <class T>
void printNode2(Node<T> & node) {
cout << node.data << " -> ";
while (node.next != nullptr) {
node = *node.next;
cout << node.data << " -> ";
}
cout << endl;
}
int main() {
Node<int> node;
Node<int> * temp = &node;
Node<int> * ref = &node;
insertlast(ref, 5);
insertfirst(ref, 3);
insertlast(ref, 6);
insertfirst(ref, 2);
//printNode(ref);
//printNode2(node);
while(ref->next != nullptr){
temp = ref->next;
delete ref;
ref = temp;
}
return 0;
}
It would be cool if you could help me out to find out what's wrong with the code. My guess is that it's something fishy with the pointer reference in insertfirst, but I can't figure it out.
Thanks in advance!
When you call insertfirst the first time, you will create a new node whose next pointer is the statically allocated node object from main, then when you loop over the list to delete the nodes in it, you will try to delete this node object.
What you should do, if you want a sentinel object at the head of the list, is to make its next pointer point to the new node, and the new node should have its next pointer set to p->next. So something like
template <class T>
void insertfirst (Node<T> * head, const T & data) {
Node<T> * tmp = new Node<T>(data, head->next);
head->next = tmp;
}
Finally a hint on how to debug these things: Draw it on paper! After every operation, draw it out on paper, and problems like this would have been very easy to spot.
In your insertlast function, if the argument p is NULL, then your code will leak an instance of Node. You create the new instance and assign its address to p, but once you leave the function, p goes out of scope and you no longer have a pointer to the newly created instance.
I suppose you wanted to pass a reference to p like in your insertfirst function, but forgot to put the & char in there.
There is inconsistent interface of these two functions
template <class T>
void insertlast (Node<T> * p, T data) {
if (p == nullptr) {
p = new Node<T>(data, nullptr);
} else {
while (p -> next != nullptr) {
p = p -> next;
}
p -> next = new Node<T>(data, nullptr);
}
}
template <class T>
void insertfirst (Node<T> * & p, const T & data) {
Node<T> * tmp = new Node<T>(data, p);
p = tmp;
}
In the first function parameters are declared like Node<T> * p, T data while in the second function they are declared like Node<T> * & p, const T & data
In the first function you also shall pass the first parameter by reference. Otherwise p is a local variable of the function and changes of it will not influence to the original argument.
In can be defined the following way
template <class T>
void insertlast ( Node<T> * &p, const T &data )
{
if ( p == nullptr )
{
p = new Node<T>(data, nullptr);
}
else
{
Node<T> *tmp = p;
while ( tmp->next != nullptr )
{
tmp = tmp->next;
}
tmp->next = new Node<T>( data, nullptr );
}
}
Also you have to initialize the first node in main to nullptr
Node<int> *node = nullptr;
It is a bad idea to define the first node of the list in the stack. It is simply an invalid design.
I'm trying to implement a linked list.
But I'm receiving an error when I try overloading the << operator.
This is my program:
#include<iostream>
#include<stdlib.h>
using namespace std;
template<class T> class List;
template<class T>
class Node
{
T data;
Node* next;
public:
Node(T val)
{
data = val;
next = NULL;
}
Node(T val, Node* link)
{
data = val;
next = link;
}
friend class List<T>;
friend ostream& operator<<(ostream& out, List<T>* li);
};
template<class T>
class List
{
Node<T>* first;
Node<T>* last;
public:
friend ostream& operator<< (ostream& out, List<T>* li)
{
if(li->first)
out<<"Empty.\n";
else
{
out<<"Displaying: \n";
Node<T>* p = li->first;
while(p)
{
out<<p->data;
p = p->next;
}
}
return out;
}
List()
{
first = last = NULL;
}
List(T val)
{
Node<T>* l = new Node<T>(val);
first = last = l;
}
void insertHead(T val)
{
if(first)
{
Node<T>* p = new Node<T>(val,first);
first = p;
}
else
first = last = new Node<T>(val);
}
void insertTail(T val)
{
if(first)
{
last->next = new Node<T>(val);
last = last->next;
}
else
first = last = new Node<T>(val);
}
void insertAt(T val, int pos)
{
//check if list is empty.
if(first==NULL)
first = new Node<T>(val);
else
if(pos==1)
insertHead(val);
else
{
Node<T>* curr = first;
int i = 1;
// iterate till position is reached.
while( i<pos )
{
curr=curr->next;
i++;
}
//create new node.
Node<T>* p = new Node<T>(val,curr->next);
//link new node to previous node.
curr->next = p;
}
}
void concatenate(List<T>* m)
{
//m is concatenated to end of *this.
if(first)
{
last->next = m->first;
last = m->last;
}
else
{
first = m->first;
last = m->last;
}
m->first = m->last = 0;
}
void delVal(int pos)
{
//if position is first, delete first node.
if( pos == 1 )
{
Node<T>* p = first;
first = first->next;
if(first==0)
last=0;
free(p);
}
//otherwise, iterate till correct position and delete the node.
else
{
int i = 1;
Node<T>* curr = first;
while( i<pos )
{
curr = curr->next;
i++;
}
Node<T>* p = curr->next;
curr->next = p->next;
if(curr->next==0)
last = curr;
free(p);
}
}
void searchVal(T val)
{
Node<T>* curr = first;
int i = 0;
cout<<"Search: ";
while( curr )
{
if( curr->data==val )
{
cout<<val<<" found at position "<<i<<endl;
break;
}
else
{
curr=curr->next;
i++;
}
}
cout<<endl;
}
void recDisplay(Node<T>* curr)
{
if(curr!=0)
{
cout<<curr->data<<endl;
recDisplay(curr->next);
}
}
void Display()
{
cout<<"Displaying: \n";
recDisplay(first);
}
void Reverse()
{
Node<T>* curr = first;
Node<T>* prev = 0;
while( curr )
{
Node<T>* r = prev;
prev = curr;
curr = curr->next;
prev->next = r;
}
first = prev;
}
~List()
{
Node<T>* p = first;
cout<<"Deleting:"<<endl;
while(first!=0)
{
free(first);
first = p->next;
p = first;
}
}
};
int main()
{
List<int>* l = new List<int>();
l->insertHead(5);
l->insertTail(6);
l->insertTail(7);
cout<<l;
}
When i execute this code, the compiler gives me the following errors:
warning: friend declaration 'std::ostream& operator<<(std::ostream&, List*)' declares a non-template function [-Wnon-template-friend]
note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
Please help.
Since they take a class template argument, your friends need to be function templates, or specializations of function templates:
// function template friend
template <typename T2>
friend ostream& operator<<(ostream& out, const List<T2>& li);
Note that one would usually overload this operator to take a reference, not a pointer, as in the example above.
The drawback is that this is probably not restrictive enough: ostream& operator<<(ostream& out, const List<Widget>& li) would be a friend of List<int>. Since this is not usually the desired behaviour, you can provide a template specialization, which would restrict friendship to the same T as that with which the class is instantiated:
// function template, declared outside of the class:
template <typename T>
ostream& operator<<(ostream& out, const List<T2>& li);
// function template specialization, declared inside the class:
friend ostream& operator<< <>(ostream& out, const List<T>& li);
I'm writing a linked list container for my homework. Using Qt 4.7 and gcc 4.4, I've found some problems in the code that I guess they are related to memory management or garbage collection.
After using the << operator to display the list, all data of list is changed. for example, after construction and setting a list like l,
std::cout<<l<<std::endl;
std::cout<<l<<std::endl;
prints:
Data = [-10, 3, 2, 8, 1, -1, -2, ] // this is correct
Data = [0, 149560240, 149560192, 149558336, 149560256, 149558320, 149560208, ]
My linked list is:
#ifndef LINKEDLIST1_H_
#define LINKEDLIST1_H_
#include <iostream>
template<class T> class LinkedList1;
template<class T> class Node;
template<class T>
class Node
{
friend class LinkedList1<T> ;
public:
Node(const T& value) :
Data(value), Next(NULL)
{
}
Node() :
Next(NULL)
{
}
T Data;
Node* Next;
};
template<class T>
class LinkedList1
{
public:
LinkedList1() :
size(-1), first(NULL)
{
}
~LinkedList1()
{
Node<T>* i = this->first;
Node<T>* j = this->first;
while(j!=NULL)
{
j=i->Next;
delete i;
i=j;
}
}
// Operations on LinkedList
Node<T>* First()
{
return first;
}
int Size()
{
return size + 1;
}
int Count()
{
int size = 0;
Node<T>* current = this->firstFirst();
while(current != NULL)
{
size++;
current = current->Next;
}
this->size = size;
return this->Size();
}
bool IsEmpty()
{
return this->Size() == 0;
}
void Prepend(Node<T>* value) //O(1)
{
value->Next = this->first;
this->first = value;
this->size++;
}
void Prepend(const T& value) //O(1)
{
Node<T>* item = new Node<T>(value);
item->Next = this->first;
this->first = item;
this->size++;
}
void Append(Node<T>* value)
{
if(this->IsEmpty())
{
this->first = value;
this->size++;
}
else
{
Node<T>* current = this->First();
while(current->Next != NULL)
current = current->Next;
current->Next = value;
value->Next = NULL;
this->size++;
}
}
void Append(const T& value)
{
Node<T>* temp= new Node<T>(value);
this->Append(temp);
}
void Insert(Node<T>* location, Node<T>* value) //O(n)
{
Node<T>* current = this->first;
Node<T>* before = current;
while(current != NULL)
{
before = current;
current = current->Next;
if(current == location)
{
before->Next = value;
value->Next = current;
this->size++;
break;
}
}
}
void Insert(Node<T>* location, const T& value)
{
Node<T>* temp = new Node<T>(value);
this->Insert(location,temp);
}
Node<T>* Pop()
{
if(this->IsEmpty())
return NULL;
else
{
Node<T>* current = this->first;
Node<T>* before = current;
while(current->Next != NULL)
{
before = current;
current = current->Next;
before->Next = current;
}
before->Next = NULL;
this->size--;
return current;
}
}
Node<T>* PopF()
{
if(!this->IsEmpty())
{
Node<T>* head = this->first;
this->first = this->first->Next;
this->size--;
return head;
}
else
return NULL;
}
Node<T>* Remove(Node<T>* location)
{
// validating by IsEmpty is not necessary for this operation,
// while statement's condition guarantees validation
Node<T>* current = this->first;
Node<T>* before = current;
while(current != NULL)
{
before = current;
current = current->Next;
before->Next = current;
if(current == location)
{
before->Next = current->Next;
current->Next=NULL;
return current;
}
}
return NULL; // Not found...
}
void Inverse()
{
if(this->IsEmpty())
return;
else
{
Node<T>* r = NULL;
Node<T>* q = this->first;
Node<T>* p = this->first;
while(q != NULL)
{
p = p->Next;
q->Next = r;
r = q;
q = p;
}
this->first = r;
}
}
// Ordered insertion. implement this: foreach i,j in this; if i=vale: i+=vale, break; else if i<=value<=j: this.insert(j,value),break
friend std::ostream& operator<<(std::ostream& out, const LinkedList1 item)
{
out<<"Data = [";
Node<T>* current = item.first;
while(current != NULL)
{
out << current->Data << ", ";
current = current->Next;
}
out<<"]";
return out;
}
void HelperOutput(std::ostream& out, const LinkedList1 item) const
{
out<<item;
}
Node<T>* operator[](const int& index)
{
int i=0;
Node<T>* current = this->first;
while(i<=index && current!=NULL)
{
if(i=index)
return current;
else
{
i++;
current=current->Next;
}
}
}
public:
int size;
Node<T>* first;
};
#endif /* LINKEDLIST1_H_ */
friend std::ostream& operator<<(std::ostream& out, const LinkedList1 item)
{
out<<"Data = [";
Node<T>* current = item.first;
while(current != NULL)
{
out << current->Data << ", ";
current = current->Next;
}
out<<"]";
return out;
}
first item in output of second call is always 0. So I Thinked I've set first to NULL in somewhere in code; but I checked out all of methods and there was nothing like that. In addition, printed value is not the pointer itself; it's pointer's Data. Somewhere somebody changes Datas of all Node<T>*s in my list.
Is this a memory management or garbage collection issue? if not, what I'm doing wrong?
One thing that stands out here is that your signature is:
std::ostream& operator<<(std::ostream& out, const LinkedList1 item)
Instead of:
std::ostream& operator<<(std::ostream& out, const LinkedList1& item)
So, you are invoking a copy of your LinkedList. I suspect the issue here is that you have not correctly implemented your copy and assignment operators for LinkedList1, such that the the copy references the original content, and the destructor is making the original object into garbage.
I would recommend adding the following to your definition of LinkedList1:
private:
// The following declarations disallow copy and assignment. Do not implement.
LinkedList1(const LinkedList1&);
LinkedList1& operator=(const LinkedList1&);
Adding the above will lead to linker errors for the original signature that you had. I would then recommend passing the linked list by const reference, and your problem should disappear.
As an aside, I notice that many of your functions can be made const but aren't. For example, you have int Size() instead of int Size()const. One should generally mark as const anything that can be so-marked. This is known as "const-correctness" and can avoid a large number of issues.
Also, minor style nitpick: you have if...else statements where one has braces and the other doesn't. I would strongly recommend that you use braces in all cases as this leads to more readable code.