I have been having trouble getting my assignment operator for a doubly-linked list to work properly. The operator works correctly when the rhs is an empty list, but if it is populated, it does not work and throws an exception error saying "read access violation".
Here is my main routine that will not run.
#include <cstdlib>
#include "linkedlist.h"
using namespace std;
int main()
{
LinkedList e1;
e1.insertToFront("A");
e1.insertToFront("B");
e1.insertToFront("C");
LinkedList e2;
e2.insertToFront("Please work");
e1 = e2; //Expecting e1 to now just hold "Please work".
system("pause");
}
Here is the assignment operator itself (in a separate header file).
// assignment operator
const LinkedList& LinkedList::operator=(const LinkedList& rhs)
{
Node* temp;
temp = head;
Node* forward;
forward = new Node;
while (temp != nullptr) // clear memory of target variable
{
forward = temp->next;
delete temp;
temp = forward;
}
if (rhs.head == nullptr)
{
head = nullptr;
tail = nullptr;
}
//GOOD THROUGH THIS PNT.
else
{
temp = rhs.head;
while (temp != nullptr)
{
this->addToEnd(temp->value);
temp = temp->next;
}
}
return *this;
}
And here is the addToEnd function that I call as well as the Node struct.
void LinkedList::addToEnd(const ItemType& val)
{
Node* temp;
temp = new Node;
temp->value = val;
if (this->head == nullptr)
{
head = temp; // make new node head if list is empty
head->next = nullptr;
head->prev = nullptr;
tail = temp;
}
else
{
temp->prev = tail; // otherwise point current tail towards temp
temp->next = nullptr;
tail->next = temp;
tail = temp;
}
return;
}
////////////////////////////////////////////////////////////////////////
struct Node
{
ItemType value;
Node* next;
Node* prev;
};
You delete the old nodes, but you neglect to set head and tail to nullptr, so those pointers still point to deleted objects. Then you try to add elements to that deleted list, and get Undefined Behavior.
When you are clearing out the existing nodes, you are not resetting your head and tail pointers to nullptr before you start copying values from the source list. So you are adding new Nodes to your list using invalid pointers.
You also have a small memory leak, as you are allocating a new Node for the forward variable and then immediately reassign forward to point at another Node if the source list is not empty. You never delete the Node you allocate with new. You should not be allocating ANYTHING when clearing out the existing nodes.
To make things a little safer, you should wrap the clearing of the list in a separate method of its own, and then you can call that method whenever needed (don't forget in the destructor, not just in the assignment operator=).
It would be even better if you implement your assignment operator= in terms of your copy constructor (you do have one, right?) using the copy-and-swap idiom. And since you are clearly using C++11 or later, you should also implement a move constructor as well. These steps will greatly simplify your operator= implementation and make it safer to use.
Try this:
class LinkedList
{
public:
LinkedList() = default;
LinkedList(const LinkedList& src);
LinkedList(LinkedList&& src);
~LinkedList();
...
LinkedList& operator=(LinkedList rhs);
...
private:
Node *head = nullptr;
Node *tail = nullptr;
...
};
#include <utility>
LinkedList::LinkedList(const LinkedList& src)
{
Node* temp = src.head;
while (temp)
{
addToEnd(temp->value);
temp = temp->next;
}
}
LinkedList::LinkedList(LinkedList&& src)
: head(src.head), tail(src.tail)
{
src.head = src.tail = nullptr;
}
LinkedList::~LinkedList()
{
clear();
}
void LinkedList::clear()
{
Node *temp = head;
head = tail = nullptr;
while (temp)
{
Node *forward = temp->next;
delete temp;
temp = forward;
}
}
LinkedList& LinkedList::operator=(LinkedList rhs)
{
std::swap(head, rhs.head);
std::swap(tail, rhs.tail);
return *this;
}
You can also simplify your insertToFront() and addToEnd() methods a little bit, too:
struct Node
{
ItemType value;
Node* next = nullptr;
Node* prev = nullptr;
Node(const ItemType& val) : value(val) {}
};
void LinkedList::insertToFront(const ItemType& val)
{
Node* temp = new Node(val);
if (!tail)
tail = temp; // make new node tail if list is empty
if (head)
{
temp->next = head; // point current head towards temp
head->prev = temp;
}
head = temp;
}
void LinkedList::addToEnd(const ItemType& val)
{
Node* temp = new Node(val);
if (!head)
head = temp; // make new node head if list is empty
if (tail)
{
temp->prev = tail; // point current tail towards temp
tail->next = temp;
}
tail = temp;
}
Related
I've created a link list class with some operations.
I am trying to merge two linked lists together, as shown in the main function. I am able to successfully do that operation and have it display on the screen.
I suspect I may be doing something wrong, though, with implementing the tail node's next pointer. When the destructor is called, I turn on the debugger to see what is going on exactly. It deletes all of the nodes successfully and shows that old->next and subsequently head do end up equaling nullptr. I made sure for the destructor to only loop when the empty operation is false for nullptr.
But, for some reason, the destructor continues looping and the program gives me the error:
LinkedList(2000,0x1000d3dc0) malloc: error for object 0x1007239d0: pointer being freed was not allocated
I know the solution may be obvious, but I am completely pooped. The destructor works fine for non-merged lists.
class Node{
public:
int data;
Node* next;
friend class LinkedList;
};
class LinkedList{
public:
Node* head;
public:
LinkedList()
{head = nullptr;}
~LinkedList()
{while (!empty()) remove();}
void addDataBack(int data);
void display();
void remove();
bool empty() const
{return head == nullptr;}
void merge(Node* list1, Node* list2);
};
void LinkedList::addDataBack(int data){
Node *p = new Node;
Node *t;
t = head;
p->data = data;
p->next = nullptr;
if (!head){
head = p;
}
else{
t = head;
while(t->next){
t = t->next;
}
t->next = p;
}
}
void LinkedList::display(){
Node *t = head;
while (t){
cout << t->data << endl;
t = t->next;
}
}
void LinkedList::remove(){
Node *old = head;
head = old->next;
delete old;
}
void LinkedList::insertNode(int index, int data){
Node *node = new Node;
int i = 0;
Node *t = head;
Node *p = nullptr;
node->data= data;
while ( t!= NULL){
if (index == i){
p->next = node;
node->next = t;
break;
}
p = t;
t = t->next;
i++;
}
}
void LinkedList:: merge(Node *list1, Node *list2){
Node* t = list1;
head = list1;
while (t->next) {
t = t->next;
}
t->next = list2;
}
int main(int argc, const char * argv[]) {
LinkedList list;
LinkedList list2;
list.addDataBack(8);
list.addDataBack(3);
list.addDataBack(7);
list.addDataBack(12);
list.addDataBack(9);
list.insertNode(2, 25);
list2.addDataBack(4);
list2.addDataBack(10);
LinkedList list3;
list3.merge (list.head, list2.head);
list.display();
return 0;
}
The code does not compile because you're missing the insert function prototype in the class definition.
See the insertNode function; in the line p->next = node, if index
is 0, then this line is going to indirect a null pointer and throw an exception.
The insertNode function will leak memory if you provide an index outside the current number of nodes - 1
The insertNode function will leak memory if the current list is empty
Here is how it should look.
void LinkedList::insertNode(int index, int data)
{
Node* newNode = new Node;
newNode->data = data;
//Wrap this up quick if the list is already empty.
if (head == nullptr)
{
head = newNode;
return;
}
int i = 0;
Node* current = head;
Node* prev = nullptr;
while (current != nullptr)
{
if (index == i)
{
newNode->next = current;
if (prev)
prev->next = newNode;
return;
}
prev = current;
current = current->next;
i++;
}
//if (index >= i)
//Either delete the new node, or throw an out of bounds exception.
//Otherwise this will result in a memory leak. Personally, I think
//throwing the exception is correct.
delete newNode;
}
Here is the main issue:
Your merge function is a bit confusing, because you are essentially creating a new list from two lists, but not via a constructor, but simply merging them. This will mean that list1 is functionally equivalent to list3, but the addresses are all intermingled. This means that when we exit the main function scope, you will be deleting memory from list1, and then when it destroys list2 it will ALSO delete them again, and list3 will do the same (though it will have crashed before then).
Why not simply make it take one list and then merge the two?
#include <iostream>
#include <string>
using namespace std;
class Node{
public:
int data;
Node* next;
friend class LinkedList;
};
class LinkedList{
public:
Node* head;
public:
LinkedList()
{head = nullptr;}
~LinkedList();
void addDataBack(int data);
void display();
void remove();
void insertNode(int index, int data);
bool empty() const
{return head == nullptr;}
void merge(LinkedList& otherList);
};
LinkedList::~LinkedList()
{
while (!empty())
remove();
}
void LinkedList::addDataBack(int data){
Node *p = new Node;
Node *t;
t = head;
p->data = data;
p->next = nullptr;
if (!head){
head = p;
}
else{
t = head;
while(t->next){
t = t->next;
}
t->next = p;
}
}
void LinkedList::display(){
Node *t = head;
while (t){
cout << t->data << endl;
t = t->next;
}
}
void LinkedList::remove(){
Node *old = head;
head = old->next;
delete old;
old = nullptr;
}
void LinkedList::insertNode(int index, int data)
{
Node* newNode = new Node;
newNode->data = data;
//Wrap this up quick if the list is already empty.
if (head == nullptr)
{
head = newNode;
return;
}
int i = 0;
Node* current = head;
Node* prev = nullptr;
while (current != nullptr)
{
if (index == i)
{
newNode->next = current;
if (prev)
prev->next = newNode;
return;
}
prev = current;
current = current->next;
i++;
}
//if (index >= i)
//Either delete the new node, or throw an out of bounds exception.
//Otherwise this will result in a memory leak. Personally, I think
//throwing the exception is correct.
delete newNode;
}
void LinkedList:: merge(LinkedList& otherList){
Node* thisTail = head;
while (thisTail->next) {
thisTail = thisTail->next;
}
thisTail->next = otherList.head;
otherList.head = nullptr;
}
int main(int argc, const char * argv[]) {
LinkedList list;
LinkedList list2;
list.addDataBack(8);
list.addDataBack(3);
list.addDataBack(7);
list.addDataBack(12);
list.addDataBack(9);
list.insertNode(2, 25);
list2.addDataBack(4);
list2.addDataBack(10);
list.merge(list2);
list.display();
list2.display();
cout << "list2 is " << (list2.empty() ? "empty." : "not empty");
return 0;
}
Final Note:
Try to avoid single letter variables unless they are used for iteration, otherwise (especially with linked lists and pointer juggling) it is very difficult to maintain, debug and receive help for.
But, for some reason, the destructor continues looping and [...]
I doubt that, but this is what might appear to be happening if you are not watching closely enough (in particular, watching the value of the this pointer). It looks to me as though the destructor of list3 will finish looping, at which point the destructor of list2 will start (destroying in the opposite order of construction). If you miss seeing this transition, it could very well look like the destructor is continuing when it is in fact being called a second time.
Since you never changed list2.head, it is still pointing at one of the nodes that had been merged into list3. When list2's destructor starts, head is still pointing at one of the nodes that had just been deleted by list3's destructor. Trying to delete that already-deleted node is an error.
Im a little confused on how to implement an copy assignment on a doubly linked List. I managed to get the copy constructor working but im sure on the assignment. Im trying to do this without the copy and swap method.
List.H
class List
{
public:
List();
~List();
List(const List& c);
List& operator= (const List& t);
private:
List *Next;
List *Prev;
Node *Head;
List.cpp
List::~List()
{
Node* move = Head;
while (move!=NULL)
{
Node *temp = move->Next;
delete move;
move = temp;
}
}
List::List(const List& c)
{
name = c.name;
Prev = c.Prev;
Next = c.Next;
Node* dummy, * current;
Head= dummy = new Node();
current = c.Head;
while (current)
{
dummy->Next = new Node(*current);
current = current->Next;
dummy = dummy->Next;
}
Node* temp = Head;
Head = Head->Next;
delete temp;
}
List& List::operator=(const List& t)
{
Next = t.Next;
return *this;
}
Would I also have to traverse each node in the assignment operator as well?
Edit
So this is what I have now. The problem is when im getting the data from the list it is null.
List& List::operator=(const List& that)
{
if (this != &that)
{
while (Head)
{
Node* temp = Head;
Head = Head->Next;
delete temp;
}
Node* dummy, * current;
Head = dummy = new Node();
current = that.Head;
while (current)
{
dummy->Next = new Node(*current);
current = current->Next;
dummy = dummy->Next;
}
dummy->Next = nullptr;
}
return *this;
}
Short answer is YES.
copy-constructor
List L1;
List L2(L1);
operator=
List L1;
List L2;
L2 = L1;
In both the cases, L1 has to be copied to L2 and L1 should be unchanged after copy or assignment. Hence content of every node has to be replicated to newly created node.
Copy Constructor looks something like this:
List::List(const List& c)
{
Node start;
Node* dummy = &start;
Node* CurrentNode = c.Head;
while (CurrentNode)
{
dummy->next = new Node(*CurrentNode);//New node created with content of *CurrentNode
dummy = dummy->Next;
CurrentNode = CurrentNode->Next;
}
dummy->next = nullptr;
Head = start.next;
}
And assignment operator like this:
List& List::operator=(const List& that)
{
if (this != &that) //avoid self assignment like List L1;L1=L1;
{
while (Head)//Delete exist nodes
{
Node* temp = Head;
Head = Head->Next
delete temp;
}
Node start;
Node* dummy = &start;
Node* thatHead = that.Head;
while (thatHead)
{
dummy->next = new Node(*thatHead);//New node created with content of *thatHead
dummy = dummy->Next;
thatHead = thatHead->Next;
}
dummy->next = nullptr;
}
return *this;
}
what is the algorithm used to write Snode* find and set& operator=( set &rhs) I just can't understand these two. I can read the code but I can't figure out why are they there. I can't understand the steps of the used algorithm.
Things I already figured out:
1. Snode is a function that gets a value and returns the node with the same data.but what do prev and previous do and what is **previous and why ahould we create a pointer to a pointer?
2. set& operator= is for overriding the = operator. but I can't understand what does it do after overriding.and why should we swap the heads of temp and rhs sets.
here's the code:
#include <iostream>
using namespace std;
struct Snode //Snode class defines a node in a list
{
char data;//a node includes a character
int count;//an integer to count the occurrence
Snode *next = NULL;//and a pointer to the next node
Snode(char data, Snode* next) : data(data), next(next) {}
};
class set
{
private:
Snode *head;//first node in the list
Snode *tail;//last node of the list
public:
set() : head(NULL), tail(NULL)
{
}
set( set &src) : head(NULL), tail(NULL)//copy constructor method
{
Snode *temp = src.head;//set head of the second list as temp to travers
while (temp)//untill the end of the list
{
// insert(temp->data);
Snode *newNode = new Snode(temp->data,NULL);//create a new node with the same data and count
newNode->count = temp->count;
//now puts it in the right place
if (!head)//if head = NULL (if sset is empty)
head = newNode;//set the new node as the first node
if (tail)//if tail != NULL (if set isn't empty)
tail->next = newNode;//set new node as the next node of current tail, so it'll be the tail
tail = newNode;
temp = temp->next;//does the same thing for all the nodes of the second list
}
}
~set()//destructor method
{
Snode *temp = head;
while (temp)//traverse the list and delete each node
{
Snode *next = temp->next;
delete temp;
temp = next;
}
}
set& operator=( set &rhs)
{
if (&rhs != this)
{
set temp(rhs);
Snode *ptr = head;
head = temp.head;
temp.head = ptr;
}
return *this;
}
bool isAvailable(char value)//checks if any node with the same data exists or not
{
return (find(value) != NULL);//if find function can't find any, there's no same node
}
Snode* find(char value, Snode **previous = NULL)
{
if (previous)
*previous = NULL;
Snode *temp = head;
Snode *prev = NULL;
while (temp)
{
if (temp->data == value)
{
if (previous)
*previous = prev;
return temp;
}
temp = temp->next;
}
return NULL;
}
bool isFirst(char value)
{
return ((head) && (head->data == value));//if head's data is equal to value returns true
}
bool isLast(char value)
{
return ((tail) && (tail->data == value));//if tail's data is equal to value returns true
}
void display()
{
Snode *temp = head;
while (temp)
{
cout << temp->data << " " << temp->count+1 << "\n";
temp = temp->next;
}
}
void insert(char value)//to insert a new value
{
Snode *temp = find(value);//if a node with the same data alreay exists
if (temp)
temp->count += 1;//increase the count by one
else
{
temp = new Snode(value,NULL);//if if a node with the same data doesn't exist
if (!head)//if list is empty
head = temp;
if (tail)//if list is not empty
tail->next = temp;
tail = temp;
}
}
int count(char value)//count the nodes by the counter temp
{
Snode *temp = find(value);//travers the set
return (temp) ? temp->count : 0;//if the list is empty return 0, else return the counter
}
void deleteFirst()//deletes the first node
{
if (head)//if list isn't empty
{
Snode *temp = head;
head = head->next;//move the head forward
if (tail == temp)//if loop faced the tail
tail = NULL;
delete temp;//delete the data
}
}
void deleteLast()//delete the last node
{
if (head)
{
Snode *last = head;
Snode *previous = NULL;
while (last->next)//move forward untill the node before the last one
{
previous = last;
last = last->next;
}
if (previous)//at the end of the list
previous->next = NULL;
tail = previous;
if (head == last)//if there's only one node
head = NULL;
delete last;
}
}
void remove(char value)//remove the node with the same data as the entry
{
Snode *previous;
Snode *temp = find(value, &previous);
if (temp)
{
if (temp->count > 1)
temp->count -= 1;
else
{
if (previous)
previous->next = temp->next;
if (head == temp)
head = temp->next;
if (tail == temp)
tail = previous;
delete temp;
}
}
} };
As you have guessed, find tries to locate a Snode containing the required character. If only that is required, you can ignore the previous parameter (it will be NULL), and previous/prev processing will just be useless.
But find is used in remove... In order to remove a node in a singly linked list, you must have the previous one point to the next one. So you must browse the list keeping a track of the previous node. That is exactly the way it is used in remove with:
if (previous)
previous->next = temp->next;
The assignment operator uses a close variant of the copy and swap idiom. But as the destructor only uses the head member, only that member is swapped: that will be enough to have the destructor of temp to destroy all nodes of the original list.
Simply tail should be set in this even if it is useless to set it in tmp. A correct implementation could be:
set& operator=( set &rhs)
{
if (&rhs != this)
{
set temp(rhs);
Snode *ptr = head;
head = temp.head;
temp.head = ptr;
tail = temp.tail; // no need for a full swap here
}
return *this;
}
I have a C++ code:
#include <iostream>
using namespace std;
struct Node;
typedef Node *NodePtr;
struct Node
{
int Item;
NodePtr Next;
};
class LinkedList
{
public:
LinkedList(); // default constructor
~LinkedList(); // destructor
void AddTail(int); // adds item to tail
private:
NodePtr Head;
};
LinkedList::LinkedList()
{
Head = NULL; //declare head as null
}
//Adding on tail
void LinkedList::AddTail(int Item)
{
NodePtr Crnt;
NodePtr node = new Node;
node->Item = Item;
node->Next = NULL;
//if head is in null declare the added node as head
if (Head == NULL)
{
Head = node;
}
else
{ //set the current to head, move the current node to current next node
Crnt = Head;
while (Crnt->Next != NULL)
{
Crnt = Crnt->Next;
}
//Add item to the tail of the linked list
Crnt->Next = node;
}
}
int main()
{
LinkedList la;
la.AddTail(30);
la.AddTail(60);
la.AddTail(90);
LinkedList lb;
return 0;
}
So my question is how do I implement a copy constructor(suppose on object lb) that makes a deep copy of the list argument and also adding code for testing the copy constructor on empty and non-empty lists?
Thanks in advance.
One of the big rules of programing is Don't Repeat Yourself (DRY). If you have a function that adds and you know it works, keep using it for add-related jobs. This means it's in your best interest to keep add dead stupid and versatile.
Applying the DRY philosophy, the Copy Constructor, assuming the AddTail method works correctly, is astonishingly simple: Call AddTail for every node in the source list.
LinkedList::LinkedList(const LinkedList & src):Head(nullptr)
{
NodePtr node = src.Head;
while (node != nullptr)
{
AddTail(node->Item);
node = node->Next;
}
}
And having a working copy constructor makes the assignment operator, thanks to the Copy and Swap Idiom, also laughably simple:
LinkedList & LinkedList::operator=(LinkedList src)
// pass by reference performs the copy
{
std::swap(Head, src.Head); // now just swap the head of the copy
// for the head of the source
return *this;
} // destructor fires for src and cleans up all the nodes that were on this list
To finish off The Rule of Three trifecta we need a destructor. This, like
the copy constructor is an application of DRY: Call your node removal function over and over until the list is empty. A removal function is an almost certain requirement of any linked list, so here I'm going to assume that there is one called Remove.
LinkedList::~LinkedList()
{
while (Head != nullptr)
{
NodePtr temp = Head;
Remove(Head);
delete temp;
}
}
So now based on two functions that a Linked List cannot function without anyway we have implemented all of the other functions required for basic maintenance. All you need are tested and bug-free Add and Remove functions and the rest comes practically free of charge.
And because the AddTail function hits one of my pet peaves... Here is a trick to greatly reduce the complexity of the function:
void LinkedList::AddTail(int Item)
{
NodePtr *Crnt = &Head; // instead of pointing where Head points, point at
// Head now we don't care if it is head or any
// other node's Next. They are all abstracted to
// the same thing: A pointer to where the next
// node can be found
while (*Crnt != NULL) // keep looking until end of list
{
Crnt = &(*Crnt)->Next; // by pointing at the next Next pointer
}
//Add item to the tail of the linked list
NodePtr node = new Node;
node->Item = Item;
node->Next = NULL;
*Crnt = node; // Now just plop the new node over top of the terminating NULL
}
The Remove function, which I'm leaving unimplemented, uses the same pointer -to-pointer trick.
try this (https://ideone.com/9lywXc using your original posted code)
LinkedList::LinkedList(const LinkedList& other):Head(nullptr)
{
cout << "copy constructor called:\n";
if(other.Head == nullptr) return;
NodePtr dummyHead = new Node;
NodePtr curr = dummyHead;
NodePtr othcurr = other.Head;
for(; othcurr!=nullptr; othcurr = othcurr->Next)
{
curr->Next = new Node;
curr = curr->Next;
cout << (curr->Item = othcurr->Item) << ",";
curr->Next = nullptr;
}
Head = dummyHead->Next;
delete dummyHead;
}
int main()
{
LinkedList la;
la.AddTail(30);
la.AddTail(60);
la.AddTail(90);
LinkedList lb(la);
return 0;
}
output:
copy constructor called:
30,60,90,
this is an improvement on user4581301 prior answer so that copy constructor is O(n) on input list size. keep track of the tail with a single extra pointer in your encapsulating list class:
class LinkedList
{
public:
LinkedList():Head(nullptr),Tail(nullptr){}
LinkedList(const LinkedList& other);
~LinkedList() = default; // destructor
void AddTail(int); // adds item to tail
private:
NodePtr Head;
//KEEP TRACK OF TAIL POINTER WITH EXTRA MEMBER
NodePtr Tail;
};
//via user4581301 response
LinkedList::LinkedList(const LinkedList & src):Head(nullptr),Tail(nullptr)
{
NodePtr node = src.Head;
while (node != nullptr)
{
AddTail(node->Item);
node = node->Next;
}
}
//Adding on tail
void LinkedList::AddTail(int Item)
{
NodePtr np = new Node{Item,nullptr};
if(Tail == nullptr && Head == nullptr)
Head = Tail = np;
else
{
Tail->Next = np;
Tail = Tail->Next;
}
}
regarding testing:
you can add functionality to spit out the contents of the list. or you can subclass it into a test extension. or you can break encapsulation like this, using operator<<() :
class LinkedList
{
public:
LinkedList():Head(nullptr),Tail(nullptr){}
LinkedList(const LinkedList& other);
~LinkedList() = default; // destructor
void AddTail(int); // adds item to tail
//breaks encapsulation but make some nice sugar to look inside
friend ostream& operator<<(ostream& s, LinkedList& l)
{
s << "list contents: ";
NodePtr c = l.Head;
for(; c!=nullptr;c=c->Next)
s << c->Item << " ";
s << endl;
return s;
}
private:
NodePtr Head;
NodePtr Tail;
};
so that
int main()
{
LinkedList la;
la.AddTail(30);
la.AddTail(60);
la.AddTail(90);
LinkedList lb(la);
cout << lb;
return 0;
}
spits out:
list contents: 30 60 90
I'm writing a copy constructor that copies for example S to R; Set R(S);. S is a sorted singly linked list containing some ints (with a dummy node in the beginning).
Set::Set (const Set &source)
{
Node* sourceNode = source.head->next;
head = new Node(0, nullptr);
Node* nodeHead = source.head->next;
Node* p;
if (!sourceNode) {
std::cout << "Empty !" << endl;
}
else{
while (nodeHead) {
for (p=sourceNode; p->next; p=p->next) {
;
}
head->next = new Node(nodeHead->value,nullptr);
head = head->next;
nodeHead = nodeHead->next;
}
}
}
Right now it crashes and if i remove head = head->next; it will set S to { 5 }.
This is the constructor:
class Node
{
public:
Node (int, Node*);
private:
int value;
Node* next;
};
Why doesn't this work? This is my first experience with pointers so keep that in mind please.
Let's assume you have a function that adds to the end of the linked list. The copy constructor in this case would be very simple:
Set::Set (const Set &source) : head(0)
{
Node* sourceNode = source.head;
while (sourceNode != NULL )
{
addToList(sourceNode->value);
sourceNode = sourceNode->next;
}
}
The addToList would be the function that adds a node to the back of the list. All the copy constructor has to do is start off with an empty list, and in a loop, add items from the source list until the number of items in the source list is exhausted. This method, given that the addToList function is coded correctly, is guaranteed to work, and avoids code duplication.
This is the easiest way to implement the copy constructor. If you have no function that adds to the back of the list, now would be the good time to add it since you will need to to have such a function in any event.
Here is some code
LinkList(LinkList const & temp) // Copy constructor
{
this->head = 0; // calling list head
Node* tempHead = temp.head; /*For temprory store of head of link list*/
while (tempHead != 0)
{
this->insertAtEnd(tempHead->data);
tempHead = tempHead->next;
}
}
void insertAtEnd(int val)
{
Node* temp = new Node;
temp->data = val;
temp->next = 0;
Node* curr = this->head;
if (curr != 0)
{
while (curr->next != 0)
{
curr = curr->next;
}
curr->next = temp;
}
else
{
this->head = temp;
}
}