Cloning a singly linked list using overloaded assignment operator - c++

I'm trying to implement a Singly linked list class in C++. I've overloaded the assignment operator to clone the list. The cloning itself seems to work fine, but the program crashes during deletion of the cloned list, which leads me to suspect if something's wrong during the copy procedure.
Any help is highly appreciated.
Here's the code for the overloaded = operator:
DLList& DLList::operator=(const DLList& iList)
{
Node *t = iList.head();
while(t != NULL)
{
push(t->data);
t = t->next;
}
return *this;
}
Here's the code for the push operation:
void DLList::push(int data)
{
Node *n = new Node;
n->data = data;
n->next = NULL;
//n->random = NULL;
n->next = _head;
_head = n;
//cout << "_head" <<_head->data<< "head->next" << (_head->next ? _head->next->data : 0)<<endl;
}
Here's the main code (where the crash happens) :
DLList *d = new DLList();
d->push(10);
d->push(20);
d->push(30);
d->push(40);
d->setRandom();
d->display("Original list"); // Displays the original list fine
DLList *d1 = new DLList();
d1 = d;
d1->display("Cloned list"); //Displays the cloned list fine
delete d; // works fine
delete d1; // Crashes here due to segmentation fault, invalid pointer access during delete called as part of destructor)
Code for destructor (if it helps):
~DLList()
{
while(_head != NULL)
{
Node *temp = _head;
_head = _head->next;
delete temp; // crashes here during first iteration for the cloned list
}
}

you are not using the assignment operator actually! You are just copying the pointer to the other pointer.
Debugging your code (or just add traces) would have showed that
you were not calling your copy code
the addresses of d and d1 are the same
So when you delete the second list you delete the same address twice.
You don't really need new here:
DLList d;
d.push(10);
DLList d1 = d; // assignment is REALLY called
d1.display("Cloned list");
the objects will be deleted when you go out of scope of your variables
If you want to test in your context, keeping the new, change
d1 = d;
by
*d1 = *d;
to activate assignment operator.
Another advice: factorize your copy code so it is shared between assignment operator and copy constructor, and the deletion code should be shared between destructor and assignment operator (to avoid memory leaks when assigning twice): Not tested, don't flame me if it doesn't compile, just tell me I'll fix it, I'm already overanswering here :)
DLList& DLList::operator=(const DLList& iList)
{
destroy(); // or you'll get memory leaks if assignment done twice
copy(iList);
return *this;
}
DLList& DLList::DLList(const DLList& iList)
{
_head = NULL; // set _head to NULL in all your constructors!!
copy(iList);
}
~DLList()
{
destroy();
}
void DLList::copy(const DLList& iList) // should be private
{
Node *t = iList.head();
while(t != NULL)
{
push(t->data);
t = t->next;
}
}
void DLList::destroy() // private
{
while(_head != NULL)
{
Node *temp = _head;
_head = _head->next;
delete temp; // crashes here during first iteration for the cloned list
}
_head = NULL; // calling destroy twice is harmless
}

d1 = d; is NOT copying DLList. Instead, you just make d1 point to the list that d pointing to. So, both d1 and d are pointing to the same list. At the end of your program, you will delete the list twice, and make your program crash.

If you wish to use the assignment operator, you need to dereference your pointers. See here:
DLList *d1 = new DLList();
d1 = d; // <------------- This line
d1->display("Cloned list"); //Displays the cloned list fine
On the highlighted line, you're setting the pointer d1 to point to the same location as d. This means that when you call delete at the end of your code, you're trying to delete the same object (d in this case) twice.
To fix your code, you should dereference your pointers:
DLList *d1 = new DLList();
*d1 = *d; // <------------- Note the dereference applied to BOTH lists.
d1->display("Cloned list"); //Displays the cloned list fine
Alternatively, you should avoid using pointers entirely if you can. For your trivial example you could simply create your objects directly.

Your problem is the statement
d1 = d;
which does a pointer assignment, and makes d1 point to the same object as d. The subsequent delete statements cause the same object (*d) to be released twice. That is undefined behaviour (of which one symptom is a crash like you describe).
The above also does not invoke DLLists copy constructor. If that is your intent, you need to do
*d1 = *d;
which makes the object pointed to by d1 a copy of the one pointed to by d. The two delete statements are also appropriate in this case.

Related

How to Initialize class member that is a pointer to a structure

I have a problem with the application crashing at the line of code where if(!head) is being referenced inside the function: insertNode(). head and tail are class members of type node*. It looks like, I am missing something in the way the class members: head, tail are initialized..
This is the runtime error: "Unhandled exception at 0x00245246 in SLinkedlist_array.exe: 0xC0000005: Access violation reading location 0x00000000."
slinkedlist.h:
typedef struct node
{
int value;
struct node* next;
} node;
class slinkedlist
{
public:
//ctor, dtor, insertNode(int, int), displayList()
private:
node* head, tail;
};
slinkedlist.cpp:
bool slinkedlist::insertNode(int value, int aftNodeVal)
{
int toinsertval = value;
int searchkey = aftNodeVal;
bool retval = false;
// If it's a new linked list
if(!head) // THIS IS WHERE THE APPLICATION CRASHES!
{
node* head = new node;
head->value = toinsertval;
head->next = NULL;
return true;
}
else //It's not a new list
{
while(head->next != NULL)
{
//some more code here...
}
}
return retval;
}
void slinkedlist::displayList()
{
while(!head)
{
do
{
cout << head->value << " " ;
head = head->next;
}
while(head->next != NULL);
}
//return void;
}
main.cpp:
int main()
{
slinkedlist *s1 = NULL;
s1->insertNode(4, -1);
s1->displayList();
while(1);
}`
The answer is simple: you have null-pointer dereference here:
slinkedlist *s1 = NULL;
s1->insertNode(4, -1);
s1->displayList();
That's what exactly the system tells to you: "Access violation reading location 0x00000000"
Solution can be like:
slinkedlist *s1 = new slinkedlist;
s1->insertNode(4, -1);
s1->displayList();
delete s1;
Or like this (why not to use just an object on the stack?):
slinkedlist s1;
s1.insertNode(4, -1);
s1.displayList();
Or more C++ way (if you NEED a pointer):
auto s1 = make_unique<slinkedlist>(); // s1 is a std::unique_ptr<slinkedlist>
s1->insertNode(4, -1);
s1->displayList();
slinkedlist *s1 = NULL;
defines a pointer to a slinkedlist and DOES initialize it Unfortunately it initializes it to NULL, a safe parking address where (usually) no object are allowed to exist. For the vast majority of CPUs (every CPU I've ever worked on) accessing this dead zone around NULL will crash the program, making it much easier to detect bugs.
There is no need for a pointer here. If you don't need pointer, don't use one. Your life will be much easier.
int main()
{
slinkedlist s1; // default initializes
s1.insertNode(4, -1);
s1.displayList();
while(1); // rethink this. If you want to hold a program open to see the output
// while debugging, place a breakpoint in the debugger.
}
Default initializing of s1 alone will not help you because it will do the absolute minimum work to initialize its member variables, and in the case of a pointer the minimum work is to do nothing and leave head and tail uninitialized and pointing (sort of. tail is NOT a pointer) to an indeterminate location. Because you aren't also asking about the compiler error you should get from assigning NULL to tail, the program is clearly not initializing tail and I'll assume the slinkedlist constructor doesn't do much.
Side note: If you have a constructor or destructor that don't do anything (and don't need to do anything) leave them out and let the compiler generate the appropriate code. Code that does not exist (and doesn't need to exist) has no bugs.
class slinkedlist
{
public:
//ctor, dtor, insertNode(int, int), displayList()
private:
node* head, tail; // the * only applies to head.
};
could be
class slinkedlist
{
public:
//ctor, dtor, insertNode(int, int), displayList()
private:
node* head = nullptr;
node* tail = nullptr;
};
if you are compiling to recent (2011 or newer) C++ Standards. You won't need a constructor, the work is done for you with the default assignments. You will still need a destructor along with a copy constructor and an assignment operator to satisfy The Rule of Three.
In older C++ Standards you need to make the constructor smarter
class slinkedlist
{
public:
slinkedlist(): head(NULL), tail(NULL)
{
}
//dtor, insertNode(int, int), displayList()
private:
node* head; // I recommend splitting the definitions up. It makes the code easier
// to read and makes it harder to make mistakes.
node* tail;
};
You will still need a destructor, a copy constructor, and an assignment operator.
Note that this also applies to node. If you dynamically allocate a node and do not explicitly set next to a value, you won't know where next points, and all of the tests like
while(head->next != NULL)
will fail horribly.

Overloading operator= in a singly linked list

I'm currently having a problem copying the contents from one list to another. The values all appear as 0 when compiled. I thought that there might be something wrong when overloading the assignment operator as the copy constructor is using its code.
Copy Constructor
ListOfDoubles::ListOfDoubles(const ListOfDoubles&e):head(NULL) {
if (this != &e) {
*this = e;
}
}
Overloaded operator=
const ListOfDoubles& ListOfDoubles::operator=(const ListOfDoubles
&doubleslist)
{
DoubleListNode *cpyPtr = NULL;
DoubleListNode* orgPtr = doubleslist.head;
if (this != &doubleslist)
{
while (head != NULL)
{
ListOfDoubles::~ListOfDoubles();
}
while (orgPtr != NULL)
{
if (head == NULL)
{
head = cpyPtr = new DoubleListNode(orgPtr->data);
}
else
{
cpyPtr->next = new DoubleListNode(orgPtr->data);
cpyPtr = cpyPtr->next;
}
orgPtr = orgPtr->next;
}
}
return *this;
}
General-purpose copy logic looks something like:
DoubleListNode * from = source.head; // copying from
DoubleListNode ** to = &head; // pointer to where we want to copy to
while (from != nullptr) // keep going until end of list. You did mark
// the end of the list, didn't you?
{
*to = new node(*from); //copy construct a new node around from and store it at to
to = &(*to)->next; // advance to
from = from.next; // advance from
}
*to = nullptr; // all done. Terminate list.
The real magic is going on up here at the double pointer: DoubleListNode ** to By having a pointer to a pointer, we don't care whether we're pointing at head, another node's next or what have you. It's just another node, so there are no special cases to cover.
You can do the above in both the copy constructor and assignment operator, though you are better off not repeating yourself and putting it in a function called by the copy constructor and assignment operator. Note that there are different assumptions about pre-existing data in the copy constructor (eg, list will be empty) and the assignment operator (eg, list may not be empty, so clear it and free all of the nodes before you begin) that need to be taken into account.
The primary alternative, as discussed in the comments above, is to use the Copy and Swap Idiom. For this, the above copy loop only exists in the copy constructor.
The input parameter of a copy constructor will never be the object being constructed, so checking for this != &e in the copy constructor is redundant.
Also, manually calling a destructor directly is illegal unless the memory was allocated with placement-new, which you are not using. You need to use delete to destroy your node instances.
Typically, you shouldn't implement the copy constructor in terms of operator=, you should do it the other way around. Let the copy constructor do its job of copying the source values, and then have operator= make a copy of the source list and take ownership of the copied data. This is commonly known as the "copy and swap" idiom.
Try this instead:
ListOfDoubles::ListOfDoubles()
: head(NULL)
{
}
ListOfDoubles::ListOfDoubles(const ListOfDoubles &e)
: head(NULL)
{
DoubleListNode *cpyPtr = NULL;
DoubleListNode *prevPtr = NULL;
DoubleListNode *orgPtr = e.head;
while (orgPtr)
{
cpyPtr = new DoubleListNode(orgPtr->data);
if (!head)
head = cpyPtr;
if (prevPtr)
prevPtr->next = cpyPtr;
prevPtr = cpyPtr;
orgPtr = orgPtr->next;
}
/* alternatively:
DoubleListNode **cpyPtr = &head;
DoubleListNode *orgPtr = e.head;
while (orgPtr)
{
*cpyPtr = new DoubleListNode(orgPtr->data);
cpyPtr = &((*cpyPtr)->next);
orgPtr = orgPtr->next;
}
*cpyPtr = NULL;
*/
}
ListOfDoubles::~ListOfDoubles()
{
DoubleListNode *orgPtr = head;
DoubleListNode *nextPtr;
while (orgPtr)
{
nextPtr = orgPtr->next;
delete orgPtr;
orgPtr = nextPtr;
}
}
ListOfDoubles& ListOfDoubles::operator=(const ListOfDoubles &doubleslist)
{
if (this != &doubleslist)
{
ListOfDouble tmp(doubleslist);
std::swap(head, tmp.head);
}
return *this;
}

Delete a list in c++

I have classes A and B. Class B has a pointer to class A as a field, pointing to a list:
struct A {
A* next;
char* txt;
...};
struct B {
A* next;
int length;
...};
I make each element of this list in this way:
void B::add_elem(char* str) {
A* tmp;
tmp = new A;
tmp->txt = str;
tmp->next = next;
next = tmp;
}
And I have to delete the list at the end. Will it be deleted by default with a destructor of class A, as I've called new A(but I made my destructors to print messages, there were no ones) or should I delete it explicitly (I've tried, it was a mistake in compilation)? Help, please.
B::~B() {
int i;
A* tmp;
cout<<"del list\n";
if (next) { // at least one elem
tmp = next;
while (tmp->next) {
tmp = tmp->next;
delete next;
cout<<"del elem\n";
next = tmp;
}
delete tmp;
}
}
The lifetime of any pointer which is created with new must be managed manually by the creator using a matching delete to free the memory.
This means that every class owning a raw pointer MUST take care of its deletion. This is usually done in the destructor. If you are using C++11 you can use a unique_ptr instead of a raw pointer which will manages his own lifetime. This will help you get rid of many error and memory leaks but will add a few more constraint to your design. In most cases those constraint are what you would actually want to have.
For a nice treatment of the memory management problems in C++ you can take a look at https://isocpp.org/wiki/faq/freestore-mgmt
Oh, it works! It turned out, that I've forgotten to give memory to some field but in the destructor I wanted to delete it. It was a complicated class: some static fields and one dynamic: a dynamic massive, each member of which is a pointer to a list.
At last, this destructor works:
set::~set() {
int i;
elem* tmp;
for(i=0; i<size; i++) {
if (table[i].next) { // at least one elem
tmp = table[i].next;
while (tmp->next) {
tmp = tmp->next;
delete table[i].next;
table[i].next = tmp;
}
delete tmp;
}
}
delete[] table;
cout<<"del set\n";
}
nirvana#lpt00:~/cpp/new$ ./a.out
new set
new list
new list
new list
new list
new list
new el
new el
del el
del el
del list
del list
del list
del list
del list
del set
Thanks everyone!

Linked List Using Classes

I have created a linked list class VW with a function Build to add nodes to the list. However, when I run the code to build my linked list, the Build function throws an "access violation" error. The error is thrown by the call tmp->NextObj() in the Build function.
If the object of class VW is newly created and the Build is called for the first time, then the condition if(tmp==NULL) in the Build function should be true, and hence the program should not enter the else section during the first call to Build. What am I missing here? Could you please help.
class VW
{
World_Obj *head;
public:
void Build(...);
};
void VW::Build(...)
{
World_Obj *newObj;
newObj = new World_Obj;
newObj->SetData(...);
newObj->SetNext(NULL);
World_Obj *tmp;
tmp = this->head;
if (tmp == NULL)
this->head = newObj;
else
{
while (tmp->NextObj() != NULL)
{
tmp = tmp->NextObj();
}
tmp->SetNext(newObj);
}
}
int main()
{
VW *g_w;
g_w = new VW;
/* Reading arguments from input file*/
g_w->Build(...);
}
The issue was the missing constructor in the class VW,
VW(){ head=NULL;}
Thanks all!
Here is a big problem:
tmp = this->head;
...
while (tmp->NextObj() != NULL)
{
tmp = tmp->NextObj();
}
tmp->SetNext(newObj);
...
delete tmp;
When the loop ends and after you do tmp->SetNext(newObj) then tmp will point to the second to last node in the list. Which you then promptly destroy by deleting it.
That means your list will now somewhere contain a node that no longer exist, and attempting to dereference it will lead to undefined behavior and most likely a crash.
The solution is simply to not delete tmp.

Seem to get segfaults from Copy Constructor?

I'm writing some C++ code for a simple "Node" class. This is basically a class used to manage a linear linked list. I normally perform this with a struct but I'm trying get a better handle of OOP and classes. What I've got thus far for the Node class is (note: the String class is my version (trimmed down) of a typical "string" class, it implements a copy constructor, assignment overload, destructor, etc. In testing it has worked great and seems completely self contained):
class Node {
public:
//Constructor
//-----------
Node() : next_(0) {} //inline (String constructor called)
//Destructor
//----------
~Node();
//Copy Constructor
//----------------
Node(const Node &);
//Operator Overload: =
//---------------------
//In conjunction with copy constructor. Protects Class.
Node & operator=(const Node &);
private:
String relatedEntry_;
Node * next_;
};
Creating one instance works fine (ie. Node node;) but when I create an instance that calls the Copy Constructor I end up with segfaults at the very end of my program, as it's cleaning up. The difference between using a struct for a linked list vs a class plays tricks with me a little and I think I'm missing something key here. Here is the implementation for the Default Constructor, Copy Constructor, and Overloaded Assignment Operator:
//Constructor inlined
//Destructor
Node::~Node()
{
Node * curr = next_;
while (curr) //cycle through LL and delete nodes
{
Node * temp = curr; //hold onto current
curr = curr->next_; //increment one
delete temp; //delete former current
}
}
//Copy Constructor
Node::Node(const Node & cp)
{
std::cout << "in CopyCon" << std::endl;
relatedEntry_ = cp.relatedEntry_; //calls String class copy constructor/assignment overload
Node * curr = cp.next_; //for clarity, for traversal
while (curr) //copies related entry structure
{
Node * oldNext = next_;
next_ = new Node;
next_->next_ = oldNext; //'next' field (assign prior)
next_->relatedEntry_ = curr->relatedEntry_; //String class copy
curr = curr->next_; //increment
}
}
//OO: =
Node & Node::operator=(const Node & cp)
{
std::cout << "in OO: =" << std::endl;
if (this == &cp)
return *this; //self assignment
delete next_; //delete LL
relatedEntry_ = cp.relatedEntry_; //String Class Assignment Overload
Node * curr = cp.next_; //for clarity, for traversal
while (curr)
{
Node * oldNext = next_; //hold onto old
next_ = new Node;
next_->next_ = oldNext; //set next to old
next_->relatedEntry_ = curr->relatedEntry_; //set this string to cp string
curr = curr->next_; //increment
}
return *this;
}
Note that using the Overloaded Assignment Function seems to work fine (no segfaults) even though it's virtually the same code... I'm assuming it has to do with the fact that both objects are already initialized before the assignment takes place?
//This seems to work ok
Node node1;
Node node2;
node2 = node1;
I've been at this bug for a couple of hours and I have got to get some rest. I'd really appreciate any insight into this. Thanks.
In the copy constructor loop, you have this line:
Node * oldNext = next_;
However, in the first round in the loop the value of next_ can by, well, anything and most likely not NULL. This means that the last node will a have a non-null pointer.
Initialize it to NULL before the loop and it should work.
You have the concepts of a List and a Node mixed up. You should write a List class which manages a sequence of Nodes. Your Node destructor is more or less how your List destructor should look, Node itself doesn't need a destructor.
What is specifically going wrong is that your Node destructor recursively calls itself when you write delete temp; this deletes the rest of the sequence of nodes but then your Node destructor loops around and tries to delete them again.