Circular doubly linked list memory deallocation - c++

I am having serious trouble cleaning up the memory of my circular linked list. I think I understand the issue though. My head pointer has, say, N allocations and my build pointer has N-1 allocations. The addback function can only have an integer and I can't use containers or vectors.
void Queue::addBack(int passed_Val)
{
if (head == nullptr) //takes care of first node when list is empty
{
head = new QueueNode;//head is my building now
cout<<"head is "<<sizeof(head)<<" bytes"<<endl;
head->val = passed_Val;
head->next = head;//this make an infinite loop
head->prev = head;
cout<<"node[0] mem allocated "<<head<<endl;
}
else
{
//build next will always have N-1 address, where N = number of addresses
//head points to. I don't want build to point to head when N=1
// have tempPtr point to old address
QueueNode* tempPrev = head->prev;//this will always point to the last node added!
QueueNode* build = new QueueNode;
build->next=head;
cout<<"build is "<<sizeof(build)<<" bytes"<<endl;
cout<<"node[1] mem allocated "<< build <<endl;
cout<<"node[1] "<< head <<endl;
build->val=passed_Val;
build->next = head;
head->prev = build;
tempPrev->next = build;
build->prev = tempPrev;
}
and my destructor looks like this
Queue::~Queue()
{
if(head !=nullptr)//needed because i don't want to deallocate head if it was never called
{
QueueNode* deletePtr = head->next;
cout<<"deallocating node[0] "<<head<<endl;
delete head;
while(deletePtr !=head)
{
delete deletePtr;
cout<<"deallocating pointer "<<deletePtr<<endl;
deletePtr =deletePtr->next;
}
}
}
I've thought about having the build pointer equal to the head pointer in the (head == nullptr) conditional but I am running into even more problems. Here is the result of my valgrind
I am thinking this line is my primary problem
==30923== Address 0x5a225e0 is 0 bytes inside a block of size 24 free'd
So if I understand correctly, I am trying to deallocate memory that has already been freed? How can I fix this in my destructor? I've tried messing around with my addback function but I end up losing nodes or more memory leaks :(

delete deletePtr;
This destroys whatever object deletePtr was referencing. Immediately afterwards:
deletePtr =deletePtr->next;
This attempts to reference deletePtr->next. As we've just determined, deletePtr's object has been destroyed, and dereferencing it becomes undefined behavior.
This may or may not be the only problem with the shown code. It's not possible to conclusively determine this without a minimum reproducible example, there may be other problems; but this is definitely one of them.

To add to the answer given by #SamVarshavchick, the code is flawed here:
delete head;
while(deletePtr != head) // <-- You are comparing deletePtr to a deleted pointer?
Given all that, the Queue destructor seems to bes more complex than it should be. The following is what I would have expected:
Queue::~Queue()
{
QueueNode* deletePtr = head;
QueueNode* nextPtr = nullptr;
while ( deletePtr )
{
nextPtr = deletePtr->next;
delete deletePtr;
deletePtr = nextPtr;
}
}
Note that there is no need to explicitly check for head being null at the beginning of the function, as the while loop will only be entered on a non-null value.

I was the destructor! Here is how I solved it
Queue::~Queue()
{
int i=1;
if(head !=nullptr)//needed because i don't want to deallocate head if it was never called
{
QueueNode* stop = head->prev;
QueueNode* deletePtr = head->next;//tractor node[1]
QueueNode* temp = head;// cutter node[0]
if(deletePtr ==head)// N=1
{
delete deletePtr;
}
else if(deletePtr == stop)//N=2
{
deletePtr = stop;
delete deletePtr;
delete head;
}
else//N >=3
{
while (temp != stop)//last node
{
delete temp; //delete node[0]
cout<<"temp "<<temp<<endl;
cout<<"deletePtr "<<deletePtr<<endl;
temp= deletePtr;// node[1]
deletePtr = deletePtr->next;//node[2]
cout<<"temp "<<temp<<endl;
cout<<"deletePtr "<<deletePtr<<endl;
}
delete stop;
}//end N>=3
}
}

Related

How to identify where the memory leak is?

I'm trying to rid my code of memory leaks but can't quite narrow down exactly where the leak is coming from.
void insertHead(T value){
if(!duplicateCheck(value)){
length++;
if(head == NULL){
head = new Node(value);
}else{
Node *temp = head;
head = new Node(value);
head->next = temp;
}
}
}
void insertTail(T value){
if(!duplicateCheck(value)){
// create the node
if(head == NULL){// insert at the insertHead
insertHead(value); //head = newNode;
}else{// Iterators through the linked list until a null is found
length++;
Node *fakeIterator = head; // once found sets the null val to newNode
while(fakeIterator->next != NULL){
fakeIterator = fakeIterator->next;
}
fakeIterator->next = new Node(value);
}
}
}
void insertAfter(T value, T insertionNode){ // seg faulting because it cant find the object oadd after
if(!duplicateCheck(value)){
Node *fakeIterator = head;
while (fakeIterator != NULL) {
if (fakeIterator->value == insertionNode) {
Node *newNode = new Node(value);
newNode->next = fakeIterator->next;
fakeIterator->next = newNode;
length++;
break;
}
fakeIterator = fakeIterator->next;
}
}
}
void clear(){
Node *fakeIterator = head;
while(fakeIterator!=NULL){
delete head;
fakeIterator = fakeIterator->next;
head = fakeIterator;
}
head = NULL;
length = 0;
}
The Clear function is called in the deconstructor and main's purpose to delete each node. I used valgrind and it said there is memory lost in all of the insert methods but again im just not sure where. I can post the valgrind output if need be
I'm assuming you've initialized the next field to null in Node constructor.
In your insertTail function, your loop condition involves pointer access, which is illegal if the pointer is null. Also, as #tadman mentioned, you're accessing a deleted element. (Note that while accessing, your head and fakeptr point to the same element. They must point to consecutive elements if you want to delete them)
Generally, compiling with the -g flag (in case of g++ or clang++) and then running valgrind would output the exact line numbers where your memory leak is taking place.
You could also use both gdb and valgrind together. Please refer this link for more info.

how to search and delete a specific node in a linked list in c++ [duplicate]

I feel as if I am not actually deleting the node and freeing up memory. I think I am just moving pointers around so when I print the linked list the list doesn't print the element I deleted. So my question is am I actually deleting the node or am I just simply rearranging the pointers so it looks like I am deleting the nodes(Essentially just breaking the links but not deleting the node)? Thank you for any help.
void SLL::deleteNode(int target){
Node *current = new Node;
Node *previous = new Node;
for (current = front->next, previous = front; current != NULL; current = current->next, previous=previous->next){
if (previous->data == target && previous == front){
front = previous->next;
delete[] previous;
return;
//This if statement deletes the element if its the front
}
else {
if (previous->data == target && previous->next == NULL){
previous = NULL;
delete[] current;
return;
//This if statement deletes the node if it is the back
}
else if (current->data==target)
{
previous->next = current->next;
delete[] current;
return;
//This if statement deletes a node if it is in the middle
}
}
}
delete[] current;
delete[] previous;
}
Node *current = new Node;
Node *previous = new Node;
This code causes memory leaks - you are never deleting this memory. You can declare pointers without memory allocation:
Node *current = nullptr;
Node *previous = nullptr;
delete will delete the memory of the pointer so you will actually delete Nodes.
But using delete[] for the Node* is incorrect, it should be used only for arrays - the memory allocated with new[]. Improper use leads to undefined behaviour.
So, to properly delete nodes delete them with operator delete.
Use memory leaks detection tools to know are there memory leaks in you program.
The code to delete a list element: say, we have pHead which points to the head of the list
(but it would give you much more if you write such things yourself):
Node* pCur = pHead;
Node* pPrev = pCur;
while (pCur && pCur->data != target) {
pPrev = pCur;
pCur = pCur->next;
}
if (pCur==nullptr) // not found
return NOT_FOUND;
if (pCur == pHead) { // first element matches
pHead = pCur->next;
} else {
pPrev->next = pCur->next;
}
// pCur now is excluded from the list
delete pCur; // deallocate its memory
Alternative Using Pointer To Pointer (Community Addition)
The above can take on new light when you use the actual pointers in the list to perform the enumeration. The following starts with pp being assigned the address of the head pointer (not the node it points to; the actual pointer itself). We walk the list until pp hold the address of a pointer that is pointing to a node with the target to delete (could be the head pointer, could be a next pointer in some node, makes no difference). The pointer being addressed is set to its own node's next value, then the target node is removed.
This really should be watched in a debugger to see how it works, but the algorithm is remarkably simple given what is really going on:
Node **pp = &pHead;
while (*pp && (*pp)->data != target)
pp = &(*pp)->next;
if (*pp)
{
Node *victim = *pp;
*pp = victim->next;
delete victim;
}
Thats all of it. And you get head-node removal without having to special case it for free. Hope this helps as well.

How do I properly delete nodes of linked list in C++

I feel as if I am not actually deleting the node and freeing up memory. I think I am just moving pointers around so when I print the linked list the list doesn't print the element I deleted. So my question is am I actually deleting the node or am I just simply rearranging the pointers so it looks like I am deleting the nodes(Essentially just breaking the links but not deleting the node)? Thank you for any help.
void SLL::deleteNode(int target){
Node *current = new Node;
Node *previous = new Node;
for (current = front->next, previous = front; current != NULL; current = current->next, previous=previous->next){
if (previous->data == target && previous == front){
front = previous->next;
delete[] previous;
return;
//This if statement deletes the element if its the front
}
else {
if (previous->data == target && previous->next == NULL){
previous = NULL;
delete[] current;
return;
//This if statement deletes the node if it is the back
}
else if (current->data==target)
{
previous->next = current->next;
delete[] current;
return;
//This if statement deletes a node if it is in the middle
}
}
}
delete[] current;
delete[] previous;
}
Node *current = new Node;
Node *previous = new Node;
This code causes memory leaks - you are never deleting this memory. You can declare pointers without memory allocation:
Node *current = nullptr;
Node *previous = nullptr;
delete will delete the memory of the pointer so you will actually delete Nodes.
But using delete[] for the Node* is incorrect, it should be used only for arrays - the memory allocated with new[]. Improper use leads to undefined behaviour.
So, to properly delete nodes delete them with operator delete.
Use memory leaks detection tools to know are there memory leaks in you program.
The code to delete a list element: say, we have pHead which points to the head of the list
(but it would give you much more if you write such things yourself):
Node* pCur = pHead;
Node* pPrev = pCur;
while (pCur && pCur->data != target) {
pPrev = pCur;
pCur = pCur->next;
}
if (pCur==nullptr) // not found
return NOT_FOUND;
if (pCur == pHead) { // first element matches
pHead = pCur->next;
} else {
pPrev->next = pCur->next;
}
// pCur now is excluded from the list
delete pCur; // deallocate its memory
Alternative Using Pointer To Pointer (Community Addition)
The above can take on new light when you use the actual pointers in the list to perform the enumeration. The following starts with pp being assigned the address of the head pointer (not the node it points to; the actual pointer itself). We walk the list until pp hold the address of a pointer that is pointing to a node with the target to delete (could be the head pointer, could be a next pointer in some node, makes no difference). The pointer being addressed is set to its own node's next value, then the target node is removed.
This really should be watched in a debugger to see how it works, but the algorithm is remarkably simple given what is really going on:
Node **pp = &pHead;
while (*pp && (*pp)->data != target)
pp = &(*pp)->next;
if (*pp)
{
Node *victim = *pp;
*pp = victim->next;
delete victim;
}
Thats all of it. And you get head-node removal without having to special case it for free. Hope this helps as well.

Deleting nodes in a doubly linked list (C++)

I have problems understanding why when I create two or more nodes (as shown below), the function void del_end()will only delete the char name[20] and not the whole node . How do I fix this problem without memory leak?
#include <iostream>
using namespace std;
struct node
{
char name[20];
char profession[20];
int age;
node *nxt;
node *prv;
};
node *start_ptr = NULL;
void del_end()
{
node *temp, *temp2;
temp = start_ptr;
if (start_ptr == NULL)
cout << "Can't delete: there are no nodes" << endl;
else if (start_ptr != NULL && start_ptr->nxt == NULL)
{start_ptr=NULL;}
else
{
while (temp->nxt != NULL)
{
temp = temp->nxt;
}
temp2=temp->prv;
delete temp;
temp->nxt= NULL;
}
}
Your code has some problems, the worst being here:
temp2=temp->prv;
delete temp2;
temp->nxt= NULL;
You're deleting the next-to-last node, leaving any pointers to it dangling, and losing the last node.
But if you post more of the real code, we can tell you more.
EDIT:
Here's a slightly cleaned-up version of del_end (and there's still plenty of room for improvement).
void del_end()
{
if (start_ptr == NULL)
{
cout << "Can't delete: there are no nodes" << endl;
return;
}
if (start_ptr->nxt == NULL)
{
delete start_ptr;
start_ptr = NULL;
return;
}
node *nextToLast = start_ptr;
node *last = start_ptr->nxt;
while(last->nxt != NULL)
{
nextToLast = last;
last = last->nxt;
}
delete last;
nextToLast->nxt = NULL;
return;
}
Note that this does not assume that the prev links are correct, which seems prudent here.
delete temp2;
WILL delete whole node.
The problem is that you appear to be trying to delete the last node, but you are in fact deleting the one right before it.
while (temp->nxt != NULL)
{
temp = temp->nxt;
}
temp2=temp->prv;
delete temp2;
temp->nxt= NULL;
This is your issue. Change it to this:
while (temp->nxt != NULL)
{
temp = temp->nxt;
}
temp2=temp->prv;
delete temp;
temp2->nxt= NULL;
And I believe it will work as intended. This saves off the next to last node, deletes the end and then sets the next to last node's nxt pointer to null, making it the last one.
If you're concerned about memory, I highly recommend learning to work with Valgrind http://valgrind.org/. It is a great tool. Valgrind divides memory leaks into 3 categories:
"definitely lost" - pointer to dynamically allocated memory is lost and there is no way to recover it
"possibly lost" - pointer to the dynamically allocated memory is pointing to the interior of a block and may be unrelated
"still reachable" - pointer to the dynamically allocated memory still exists, but the memory was never freed at the end of the programs execution
Running Valgrind is also very simple. Here's a link to the User Manual http://valgrind.org/docs/manual/manual.html. Some useful flags when running valgrind:
--leak-check=<no|summary|yes|full>
--show-reachable=<no|yes>
Now, the way I would remove a node in a doubly-linked list is:
// if the node to be removed is the head node
if (nodeToRemove->prev == NULL) {
// reassign the head node pointer
start_ptr = nodeToRemove->next;
} else {
// correct previous node pointer
nodeToRemove->prev->next = nodeToRemove->next;
}
// if the node to be removed node is the tail node
if (nodeToRemove->next == NULL) {
// reassign the tail node pointer
end_ptr = nodeToRemove->prev;
} else {
// correct next node pointer
nodeToRemove->next->prev = nodeToRemove->prev;
}
// deallocate memory
delete(nodeToRemove);
nodeToRemove = NULL;
Just declare node *end_ptr = NULL; after you declare start_ptr and when you append a node to the list, make sure the end_ptr is always pointing to the end of the list... and if you're adding to the end of the list, its easy... just point the end_ptr to the node being added.
You might as well keep a tail pointer, if you always have to delete the last node. So once you have the node you want to delete, I just check if its the head/tail node, reassign the next/prev pointers, and free the memory.
Btw... I took this from my C implementation, so if the syntax is off I apologize... but the logic is there.
Hope that helps.

Simple C++ Linked List

I have plenty of previous experience with linked lists in Java, but I seem to have confused myself with this simple attempt in C++. I am getting a segmentation fault at runtime, which from what I understand has to do with assigning a null pointer, but I am at a loss for a solution.
Edit: Thank you all for the very helpful responses. The code is now working, but trying to use delete p; at the end of linkedList::addNode results in a segmentation fault at runtime. Just curious if anyone knew why that is?
Here is my updated code:
#include <iostream>
using namespace std;
class Node{
public:
int data;
Node * next;
Node(int x){
data = x;
next = NULL;
}
Node(int x, Node * y){
data = x;
next = y;
}
};
class linkedList{
Node *head;
public:
linkedList(){
head = NULL;
}
void addNode(int value){
Node *p;
if(head == NULL)
head = new Node (value, NULL);
else{
p=head;
while(p->next !=NULL)
p=p->next;
p->next = new Node (value, NULL);
}
}
void print(){
Node * p;
p = head;
while(p != NULL){
cout << p->data << "\n";
p = p->next;
}
}
};
int main(void){
linkedList test;
test.addNode(4);
test.addNode(76);
test.addNode(12);
test.print();
return(0);
}
First, in linkedList::addNode method, you have the construction if (head = NULL), which will wind up assigning to head; you want the == operator.
Second, about the line:
head = &(Node (value, NULL));
For somewhat unintuitive reasons, this won't work. You'll get a reference to a Node, but that node will go out of scope as soon as the method ends, and attempts to reference it will lead to a segmentation fault. You need to use the new operator (same with the other similar line):
head = new Node(value, NULL);
If you add a method for removing a node, make sure to delete the node then—it won't get automatically garbage-collected like it will in Java.
Sidebar: Think of what happens like this: when you do Node(value, NULL), you're using a temporary variable that's declared like this:
Node hiddenTempNode(value, NULL);
This doesn't allocate space for an object anywhere except on the stack—it's very similar to allocating space for an int and a Node * on the stack as separate variables. As a result, as soon as you leave the method, the object disappears and the pointer to it will do weird things when used.
Third, beware: you may want to set next = NULL in your single-parameter constructor, to ensure that it always has a value. Similarly for your default constructor.
Fourth: your linkedList::print method is looping until p->next is NULL and printing the value of p->next; those occurrences of p->next should probably be changed to just p if you want to get the first and last items.
you are taking the address of variables on the stack
head = &(Node (value, NULL));
should be changed to
head = new Node(value, NULL);
same for the p->next code. Then you will want to delete these nodes in your destructor.
As for the printing try
while(p != NULL)
{
cout << p->data << "\n";
p = p->next;
}
You are allocating space for nodes on stack and grabbing its address, which will go away as soon as the block ends and consequently, the address will be rendered invalid. You should allocate nodes using new operator on the heap instead:
Node* node = new Node(value, NULL);
You should free everything you allocate on the heap as soon as you don't need it to prevent memory leak:
delete node;
For starters
if(head = NULL)
is an assignment, not a check for equality. Change it to
if(head == NULL)
Secondly,
head = &(Node (value, NULL));
Doesn't make sense* change this to
head = new Node (value, NULL);
*this actually creates a temporary object, gives you the address, then destroys that newly created object.
Thirdly,
Node(int x) { data = x; }
Leave next without a value, change this line to
Node(int x) { data = x; next = NULL; }
You are not allocating memory.You should use new to allocate it.
One more error in if(head = NULL) , it should be if(head == NULL)
void addNode(int value){
Node *p;
if(head == NULL)
head = new Node (value, NULL);
else{
p=head;
while(p->next !=NULL)
p=p->next;
p->next = new Node (value, NULL);
}
}
I'd like to add two issues that were not mentioned, yet:
when you 'new' objects, you must 'delete' them at some point.
all three of your constructors should initialize both member variables.
Your delete statement is not actually doing any cleanup. By the time you call it p==null. If you want to cleanup the list, you will need to implement a separate method to iterate through, and delete each and every node.
Something like this:
void ClearList ()
{
Node * c = head;
Node * n;
while (c != NULL)
{
n = c->next;
delete c;
c = n;
}
}
The code is now working, but trying to
use
delete p;
at the end of linkedList::addNode
results in a segmentation fault at
runtime. Just curious if anyone knew
why that is?
Well this is an issue because the purpose of the add node function was to dynamically allocate a new node at the end of the LinkedList. So you do that correctly, now by putting 'delete p;' you are deleting the newly added node (something I imagine you don't actually want). However, to answer your question which is why this causes a segmentation fault:
You add a node, you tell head to point to this new node. Now you delete this new node without telling head that it should once again point to NULL. Thus next time you add a node, or try to print your list, it will immediately attempt to look at what head is pointing to, which is in fact released (deleted) memory, kaboom?
The correct (or at least one correct) usage of delete in your list is in a destructor, remember in C++ we always want to clean up the dynamic memory that we have allocated, your destructor might look like:
~linkedList()
{
Node* p = head;
while ( p!=NULL )
{
Node* nextNode = p->next;
delete p;
p = nextNode;
}
}
By using a destructor like this you guarantee that your linkedList will be cleaned up appropriately when it goes out of scope, or is deleted.
Solution: Don't implement your own linked list. Use the one supplied by the standard library.