This is a school assignment and I have most of it under control, but there is a small part that is creating a memory leak and I have no more ideas on how to fix it.
We have created a memory allocator, and the trouble part are this two functions.
This first one cannot be modified
void destroy (){
free():
tot_alloc = 0; }
This second one is the one I'm working on
void free(){
munmap(pool, PAGE_SIZE);
Page* f = this;
f = f->prev;
if (f != NULL)
f->destroy();
}
I have written all of the free() function and was asked in the assignment to call destroy().
I realize that this function is not destroying the first "this" because immediately is going to f->prev but I have no clue how to make it first destroy this and the go to prev.
I hope this is not a too silly question.
Many thanks!
Nico
To remove an element from a singly-linked list, you must walk to that element to find the element before it in the list. Then you have to 'stitch' around it. Like this:
void free()
{ // Note: This has no error checking!
Page *f = tail, *next_f = NULL;
while(f != this)
{ // find this node to find the node after this node
next_f = f;
f = f->prev;
}
// found it. Now, next_f is the node after this node.
// close the chain so this link can go away
if (next_f == NULL) // there is no node after us, we must be the tail
tail = prev; // the tail is now whatever node is after us
else // in the node after us, the node before it is now the node before us
next_f->prev = prev;
destroy(); // we are unlinked from the chain so can now be freed
}
Related
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;
In function given below, I simply delete the head-pointer of the list and set head pointer to nullptr (im setting it nullptr because in my print function,I check for nullptr for head node, and ask user to create list first if head-node is nullptr).
void del_list(stud* &orig_head)
{
cout << "Deleting entire list..." << endl;
delete orig_head;
orig_head = nullptr;
}
I have a question regarding the way I choose to delete the list, since im not clearing each node of list, im simply clear the head pointer, what will happen to all the other nodes? Will this approach create a memory leak ?
Edit:
Im not using OOP to implement linked list,im implementing linked list using struct and couple of functions.
I like to handle this problem recursively:
void deleteNode(Node * head)
{
if(head->pNext != NULL)
{
deleteNode(head->pNext)
}
delete head;
}
If we have a list of 5 items:
head->pNext->pNext->pNext->pNext->NULL;
Then, the function will first get called for head, then for each pNext until the last one. When we reach the last one, it will skip deleting the next one (since it's null) and just delete the last pNext. Then return and delete the list from back to front.
This is assuming that each node's pNext is initialized to NULL. Otherwise, you'll never know when you've reached the end of the linked list.
Your code will cause memory leak. To delete it correctly, traverse the list and while traversing delete each node separately. And finally make head pointer to point to NULL value. You can have a look at the following code.
void deleteList(struct Node** head_ref)
{
struct Node* current = *head_ref;
struct Node* next;
while (current != NULL)
{
next = current->next;
free(current);
current = next;
}
//Now make head_ref point to null
*head_ref = NULL;
}
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;)
I have recently managed to get a stack overflow when destroying a tree by deleting its root 'Node', while the Node destructor is similar to this:
Node::~Node(){
for(int i=0;i<m_childCount;i++)
delete m_child[i];
}
A solution that come up into my mind was to use own stack. So deleting the tree this way:
std::stack< Node* > toDelete;
if(m_root)
toDelete.push(m_root);
while(toDelete.size()){
Node *node = toDelete.top();
toDelete.pop();
for(int i=0;i<node->GetChildCount();i++)
toDelete.push(node->Child(i));
delete node;
}
But in there the std::stack::push() may throw an exception. Is it possible to write an exception free tree destruction? How?
EDIT:
If anybody is interested here is an exception free non-recursive code inspired by the algorithm pointed out by jpalecek:
Node *current = m_root;
while(current){
if(current->IsLeaf()){
delete current;
return;
}
Node *leftMostBranch = current;// used to attach right subtrees
// delete all right childs
for(size_t i=1; i<current->GetChildCount(); i++){
while(!leftMostBranch->Child(0)->IsLeaf())
leftMostBranch = leftMostBranch->Child(0);
delete leftMostBranch->Child(0);
leftMostBranch->Child(0) = current->Child(i);
}
// delete this node and advance to the left child
Node *tmp = current;
current = current->Child(0);
delete tmp;
}
note: Node::IsLeaf() is equivalent to Node::GetChildCount()!=0.
I just had this as an interview question.
And I must admit this is one of the hardest things I had to solve on the fly.
Personally I don't think it's a good question as you may know the trick (if you have read Knuth) in which case it becomes trivial to solve but you can still fool the interviewer into making him/her think you have solved it on the fly.
This can be done assuming that the node stores child pointers in a static structure. If the node stores child pointers in a dynamic structure then it will not work, as you need to re-shape the tree on the fly (it may work but there is no guarantee).
Surprisingly the solution is O(n)
(Technically every node is visited exactly twice with no re-scanning of the tree).
This solution uses a loop (so no memory usage for stack) and does not dynamically allocate memeroy to hold nodes that need to be deleted. So it is surprisingly effecient.
class Node
{
// Value we do not care about.
int childCount;
Node* children[MAX_CHILDREN];
};
freeTree(Node* root)
{
if (root == NULL)
{ return;
}
Node* bottomLeft = findBottomLeft(root);
while(root != NULL)
{
// We want to use a loop not recursion.
// Thus we need to make the tree into a list.
// So as we hit a node move all children to the bottom left.
for(int loop = 1;loop < root->childCount; ++loop)
{
bottomLeft->children[0] = root->children[loop];
bottomLeft->childCount = std::max(1, bottomLeft->childCount);
bottomLeft = findBottomLeft(bottomLeft);
}
// Now we have a root with a single child
// Now we can delete the node and move to the next node.
Node* bad = root;
root = root->children[0];
delete bad; // Note the delete should no longer destroy the children.
}
}
Node* findBottomLeft(Node* node)
{
while((node->childCount > 0) && node->children[0] != NULL))
{ node = node->children[0];
}
return node;
}
The above method will work as long as their is always a children[0] node (even if it is NULL). As long as you do not have to dynamically allocate space to hold children[0]. Alternatively just add one more pointer to the node object to hold the delete list and use this to turn the tree into a list.
This is what all garbage collectors struggle with. However, the best thing you can do (IMHO) is to pray for enough memory for the stack, and your prayers will be heard 99.99999% of the time. Should it not happen, just abort().
BTW if you are interested, there is a solution to traverse long (and deep) trees without allocating much memory.
Why is the original code throwing an exception? I'm guessing you are doing something like using the same node object in multiple places in the tree. Stack overflows are rarely caused by normal expected situations. Stack overflows are not a problem, they are the symptom of a problem.
Rewriting the code differently won't fix that; you should just investigate & fix the error.
Is it possible to write an exception free tree destruction? How?
Perhaps this (untested code):
void destroy(Node* parent)
{
while (parent)
{
//search down to find a leaf node, which has no children
Node* leaf = parent;
while (leaf->children.count != 0)
leaf = leaf->chilren[0];
//remember the leaf's parent
parent = leaf->parent;
//delete the leaf
if (parent)
{
parent->children.remove(leaf);
}
delete leaf;
} //while (parent)
}
I am having a problem with delete and destructor (I am sure I am making a stupid mistake here, but haven't been able to figure it out as of yet).
When I step through into the destructor, and attempt to call delete on a pointer, the message shows up "Cannot access memory at address some address."
The relevant code is:
/*
* Removes the front item of the linked list and returns the value stored
* in that node.
*
* TODO - Throws an exception if the list is empty
*/
std::string LinkedList::RemoveFront()
{
LinkedListNode *n = pHead->GetNext(); // the node we are removing
std::string rtnData = n->GetData(); // the data to return
// un-hook the node from the linked list
pHead->SetNext(n->GetNext());
n->GetNext()->SetPrev(pHead);
// delete the node
delete n;
n=0;
size--;
return rtnData;
}
and
/*
* Destructor for a linked node.
*
* Deletes all the dynamically allocated memory, and sets those pointers to 0.
*/
LinkedListNode::~LinkedListNode()
{
delete pNext; // This is where the error pops up
delete pPrev;
pNext=0;
pPrev=0;
}
It seems that you are deleting the next and previous nodes of the list from the destructor. Which, if pNext and pPrev are LinkedListNode*, means that you are recursively deleting the whole list :-(
Try this:
std::string LinkedList::RemoveFront()
{
LinkedListNode *n = pHead->GetNext(); // the node we are removing
std::string rtnData = n->GetData(); // the data to return
// un-hook the node from the linked list
pHead->SetNext(n->GetNext());
n->GetNext()->SetPrev(pHead);
n->SetNext(0);
n->SetPrev(0);
// delete the node
delete n;
n=0;
size--;
return rtnData;
}
LinkedListNode::~LinkedListNode()
{
}
(Actually you don't even need to reset the prev and next pointers to 0 since you are going to delete the node anyway. I left those statements in because they at least put the node into a consistent state, which is a good idea in general. It may make a difference if you later e.g. change your memory management strategy and decide to store unused nodes for later reuse.)
It seems that your LinkedListNode is deleting its neighbours, so when you delete one node it then proceeds to destroy the entire list - note you don't set pNext and pPrev to NULL when you remove your node.
Also your LinkedListNode destructor is problematic even in the case when you want the whole list to be destroyed: having both delete pNext and delete pPrev will lead to multiple calls of the same destructor (and I think eventually a stack overflow).
Actually you shouldn't be messing with neighbours in a node. That's for list class to do - connect them properly. In the destructor you can set them to null, but unless you have allocated dynamically something else - you don't have to call delete