Linked list destructor - c++

I'm studying C++ on my own time, and writing a linked list to try and get the hang of it. I'm worried about the way I've come up to delete the object. It's a singly linked list. Here's the destructor:
template <typename T>
LinkedList<T>::~LinkedList()
{
Node<T> * current = this->first;
do {
Node * temp = current->next;
delete current; // THIS JUST MIGHT BE A TERRIBLE IDEA!!!
Node * current = temp; // new current-- might work with the current
// delete a line above
} while (current->next != 0); // need to leave this->last so that I don't
// delete it twice in the next line.
// Just realized I'm deleting this->first, then
// in the next line [implicitly] deleting it again!
//
delete this;
}
I create a pointer to the first node in the list, create a temporary pointer to the next node, delete the first pointer, create a new pointer with the same name, which then loops back. After it's done, it deletes the 'this' pointer.
I'm sure you can see why I'm worried with the way I create a new pointer with the same name as a deleted pointer.

Don't delete this in the destructor.
If Node is a template, then you need to write Node<T> in all of those definitions.
Don't redefine current, just assign it a new value.
Other than that, I don't see any other problems in this snippet.

Why not compile the code, try it, and see what happens? The worst thing that would happen would be that your program crashes and you have to figure out why.
Your code should basically work except that you need to test current in the while loop condition instead of current->next and it is redundant (and probably wrong) to write delete this in a destructor, and there are some more errors that Cat Plus Plus pointed out in his answer.
If you're trying to learn C++, then you should learn more of it to the point where you understand the mistakes you made here and are confident that the fixed code will work.
Here is my fixed version of the function:
template <typename T> LinkedList<T>::~LinkedList()
{
Node<T> * current = this->first;
while(current != 0) {
Node<T> * temp = current->next;
delete current;
current = temp;
}
delete this;
}

I don't see the question but I see lots of errors:
template <typename T>
LinkedList<T>::~LinkedList()
{
Node<T>* current = this->first; // you never check if this->first is 0
do {
Node * temp = current->next;
delete current; // THIS is not a problem
Node * current = temp; /* this line has no effect -
you define new variable and it disappears when reaches
the end of its scope next line */
} while (current->next != 0); /* 'current' is always 'this->first' but
even if you would assign it 'temp' like you intended few lines
above you never check if 'current' is 0 so you will
dereference 0 when you reach the end of the list */
delete this; /* this line is total nonsense
if your LinkedList is created with 'new LinkedList' then
you have infinite recursion (you call destructor from destructor)
otherwise you 'delete' pointer that you never 'new'-ed */
}
The correct code is this:
template <typename T>
LinkedList<T>::~LinkedList()
{
Node<T>* current = this->first;
while (current != 0)
{
Node<T>* temp = current->next;
delete current;
current = temp;
}
}

~LinkedList
{
//...
delete this;
}
delete this; in a destructor is like a code-suicide. Your object is already getting destructed and you are again destructing with delete this;. It's an undefined behavior. You can remove that. Rest of things look fine (assuming that this->first gives the head Node).
Edit: I missed that, you have redefined current. Remove that. (should be simply current = temp;)

Related

Why can't I use 'delete' for this line?

I've started to learn linked lists today, and I am trying to delete nodes.
void deleteEnd(Node* refNode) {
Node* lastNode;
lastNode = new Node;
while((refNode->next)->next != NULL) {
refNode = refNode->next;
}
lastNode = refNode->next;
refNode->next = NULL;
delete lastNode;
}
void deleteIndex(Node* refNode, int index) {
Node *prev, *next, *deleted;
prev = new Node;
next = new Node;
deleted = new Node;
for(int i=1; i < index; i++) {
refNode = refNode->next;
}
prev = refNode;
deleted = prev->next;
next = deleted->next;
prev->next = next;
free(deleted);
}
I can use delete in the first one, but when I try to use it in the second, it doesn't work. The terminal doesn't give any error messages.
I found some information on the Internet, but I couldn't really understand it.
This is my linked list:
class Node {
public:
int data;
Node *next;
};
As pointed out by the comments, there are several things wrong with this code. All issues are from the comments, none are found by me, all credit goes to François Andrieux, Jesper Juhl, Sven Nilsonn, Avi Berger, and Thomas Matthews.
First, the code probably doesn't work because you mixed new and free. new is a C++ API function, while free is from C. Whenever you construct an object with new, which should not be that often with C++'s automatic memory management, you must free it with delete.
Second, when looping through a list, always start at 0. The only reason otherwise would be to start at the second item.
Third, in this passage:
prev = new Node;
...
prev = refNode;
...
prev->next = next;
When you set prev, it is overwriting the previous value. If this is a pointer, as it is, then this causes a memory leak. Always delete it before overwriting.
Finally, in deleteEnd, as pointed out by Thomas Matthews, you are trying to dereference, or get the value from, the pointers, without checking if it is nullptr. If one is, it will cause undefined behavior, and can crash the program.

Linked List destructor without head?

I'm stuck on a linked list destructor for my class. This is what I have here:
LinkedList::~LinkedList()
{
LinkedList *forward = nullptr;
LinkedList *current = this;
//iterate through list, deleting each element as we go
while (current != nullptr)
{
//set next pointer to current's next
forward = current->next;
delete current; //delete the current memory
current = forward; //reset current to next's pointer
}
}
When I run it, I get a seg fault. I only want to delete just one node from my linked list. Is that possible? Also, I wasn't given a "head" pointer as I was used to from other lists, so I used "this" instead, does that work?
Aka - the .cpp is finding the spot in the linked list to delete, reorganizing the next pointers around it, and then deleting the node (which calls this destructor)
(when I run my program with an empty destructor, it prints out fine, but of course there are memory leaks)
Any help is appreciated!
by definition delete calls LinkedList::~LinkedList, so you have several (in fact infinite) calls to it because of the loop calling delete, so you access to already deleted element with an undefined behavior
just do
LinkedList::~LinkedList()
{
if (next != nullptr)
delete next;
}
or just
LinkedList::~LinkedList()
{
delete next; // delete on nullptr does nothing
}
even personally I prefer to compare to nullptr first
I argee with bruno.
Besides, when you want to delete a node and you don't have the pointer to head, you need a double-linked list.
The double-linked list has two pointers to its prev and next node.
when you need to delete a node, like this:
ListNode* p;
if(p->pre)
p->pre->nxt = p->nxt;
if(p->nxt)
p->nxt->pre = p->pre;
p->nxt = p->pre = NULL;
delete p;

Deleting a node from a doubly linked list AND freeing up its space as well

I'm working on an assignment and there's a problem I'm stuck on. So I'm making a doubly linked list. I want a a delete function that will take item as argument, search for that argument in the list. when it has found the node which contains that item, I have to DELETE that node. I am aware of how I would change the previous and next pointers to the the nodes around that node. The problem that has been bugging me however, is that when I just change the next pointer of the node before it and the previous pointer of the node after it, like in the code below, the particular node will only be disconnected from the list but it will still remain in the freestore. How do I delete it from there so that the memory it is taking is also freed?
The following is the code I have. Please take a look:
template <class T>
void LinkedList<T>::deleteElement(T item)
{
ListItem<T> *curPtr;
curPtr = searchFor(item); // this function returns the pointer to the node which contains the item.
(curPtr->next)->prev = curPtr->prev;
(curPtr->prev)->next = tempPtr->next;
}
So you see, the curPtr is being disconnected, but I believe it still exists somewhere on the freestore. How do I get rid of it permanantly?
Could you make an erase_next() method for your ListItem type?
I have something like the following in a similar class. Hope it helps.
void erase_next() {
// ensure it is not the last item
if(this->next != nullptr) {
// create a temporary pointer
ListItem<T>* tmp = this->next
// link next to the next item to the next item and change the
// next items previous item to this item
this->next = this->next->next;
next->prev = this;
// delete the old next item
delete tmp;
}
}
In your function you could call it with something like the following. Thanks to #davmac edits have been made to delete the first item
template <class T>
void LinkedList<T>::deleteElement(T item)
{
ListItem<T> *curPtr = searchFor(item);
if(curPtr->prev == nullptr) {
curPtr->next->prev = nullptr;
delete curPtr;
} else {
curPtr->prev->erase_next()
}
}
Edit:
I played around with this again, and you should be able to optimize the erase_next() function with the following
void erase_next() {
if(this->next != nullptr) {
this->next = this->next->next
// We've already linked next so we can delete the handle
// with prev Note: this method is not possible with a
// single linked list and we would need the temp variable
delete this->next->prev
next->prev = this;
}
}
That way you don't have to declare a temp variable.

My destructor does not appear to hit every node in the tree as I have memory leaks, what am I missing here?

EDIT: So I'm an idiot and forgot to SSH my updated .cpp when working with valgrind. Anyways I've updated the code below to represent new changes. Unfortunately I'm still getting some leaking with the stuff below and I'll I'm doing is creating a tree which means somewhere some information is still not being deleted properly.
Here is my destructor for my tree which calls the recursive helper.
//---------------------------- destructor --------------------------------
BinTree::~BinTree() {
makeEmptyHelper(root);
}
//---------------------------- makeEmptyHelper --------------------------------
void BinTree::makeEmptyHelper(Node*& current) {
if (current != NULL) {
makeEmptyHelper(current->left);
makeEmptyHelper(current->right);
delete current->data;
delete current;
current = NULL;
//delete current;
}
}
Here is my node struct:
struct Node {
NodeData* data; // pointer to data object
Node* left; // left subtree pointer
Node* right; // right subtree pointer
};
NodeData is a separate object class that has its own destructor which works properly.
You should delete current before you set it to NULL, not afterwards. In fact, there is no reason to set current to NULL in the first place: the pointer current is passed by value, so updating it has no external effect.
Note that it is legal to delete NULL, but it is a no-op.

Removing a node from a linked list in c++

I'm trying to learn C++ and there is a small confusion I have.
The text which I am learning from tells me that if I want to delete a node of type const T& I should first create a new pointer of that node type, then delete it using the inbuilt C++ delete[]. However, what happens if I just set the link from the to-be-deleted node's previous element to the to-be-deleted node's next element? Something like:
*p = node.previous;
p-> next = node.next;
Or will this cause a memory leak?
I'm confused because I read somewhere else to never, ever delete pointers willy-nilly, but the example code I am working with has something along the lines of:
Node<T> *p = node-to-be-deleted;
delete p;
What is the best way to delete the node?
Assuming your node looks like this:
struct Node
{
Node* previous;
Node* next;
SomeType data;
};
Then:
*p = node.previous;
p-> next = node.next;
Then YES. This will cause a memory leak.
It also leaves p->next->prev pointing at the wrong node.
I'm confused because I read somewhere else to never, ever delete pointers willy-nilly, but the example code I am working with has something along the lines of:
Yes the best way is to "never delete pointers". But this has to go along with some context. You should not be deleting pointers manually because pointers should be managed by an objects that control their lifespan. The simplest of these objects are smart pointers or containers. But for this situation that would be overkill (as you are creating the container).
As you are creating the container (a list) you will need to do the management yourself (Note C++ already has a couple of lost types std::list for a list of values of type t or boost::ptr_list for a list of pointers to T). But it is a good exercise to try and do it yourself.
Here is an example on code review of a beginner making a list and the comments it generated:
http://codereview.stackexchange.com: Linked list in C++
I hope this helps in explains on how to create and delete objects.
Node* p = new Node; // This is how you allocate a node
delete p; // This is how you delete it
The delete[] operator should be used on dynamically allocated arrays:
Node* nodelist = new Node[ 4 ]; // nodelist is now a (dynamically allocated) array with 4 items.
delete[] nodelist; // Will delete all 4 elements (which is actually just one chunk of memory)
Deleting a Node directly only makes sense if Node implements a destructor to update the previous and next pointers of the surrounding Node instances, eg:
Node::~Node()
{
if (previous) previous->next = next;
if (next) next->previous = previous;
}
Node *p = node-to-be-deleted;
delete p;
Otherwise, you have to update the Node pointers before then deleting the Node in question, eg:
Node *p = node-to-be-deleted;
if (p->previous) p->previous->next = p->next;
if (p->next) p->next->previous = p->previous;
delete p;
With that said, the best approach is to no implement a linked list manually to begin with. In C++, use a std::list container instead, and let it handle these details for you.
void deleteNode( Node * p )
{
Node * temp = p->next;
p->data = p->next->data;
p->next = temp->next;
free(temp);
}
Heres something i did a few months ago.
template <class T>
T LinkedList<T>::remove(int pos)
{
if (pos < 1 || pos > size)
{
throw pos;
}
ListNode * temp;
if (pos == 1)
{
temp=head;
head = head->next;
}
else
{
int i=1;
ListNode * prev = head;
while(i<pos-1)
{
i++;
prev=prev->next;
}
temp = prev->next;
prev->next = (prev->next)->next;
}
--size;
return temp->item;
}