C++ Binary Tree recursive destructor issue - c++

I made a binary tree class which holds:
int value, BinaryTree* left, BinaryTree* right.
class BinaryTree {
private:
int value;
BinaryTree* left;
BinaryTree* right;
bool isVisited;
public:
BinaryTree();
BinaryTree createComplete(int n);
~BinaryTree();
}
My destructor is :
BinaryTree::~BinaryTree() {
delete left;
delete right;
}
When running in clion it works perfectly, but in my terminal I get
a segfault (core dumped). Everywhere I looked people claimed that this should be the destructor. Any elaboration would help!
I am not a stackoverflow expert , I updated my ~BinaryTree function to still gets a segfault :
BinaryTree::~BinaryTree() {
if (right != NULL) {
delete right;
}
if (left != NULL) {
delete left;
}
}

First of all your current implementation is not that of a complete tree.
It is a node, thus I suggest renaming it to BinaryTreeNode and using it to construct a new class BinaryTree, that keeps track of the root and allows you to recursively deallocate the tree.
Having said that your destructor most likely segfaults because you are blindly attempting to delete a pointer.
First make sure you initialize left and right to nullptr.
Then you do if(left != nullptr) { delete left }

Without seeing your constructor, I assume you don't initialize your node's children to NULL. That might mean that the uninitialized nodes left and right at the bottom leaves have a random value in them. When the destructor runs, it will try to free the memory that the random garbage in the nodes point to.
Try initializing your child nodes to NULL when ctoring nodes, then making a check for it like monoceres suggested. It will also be good to set the pointer to NULL after delete to avoid situation of erronous double delete

So after debugging I noticed that the every right child is loosing it's nodes , which while going in a pre order traversal is fine , but when deleting it casuing the problem , thanks for the help every one !

Related

c++ pass a custom struct through a function

I have been working with this C++ program for a while, and I have figured what exactly is happening, but I haven't figured out how to fix it exactly. Here is what I have set up:
struct entry {
string foo;
string bar;
string num;
};
struct node {
entry input;
node* left;
node* right;
};
node* home = new node;
This code takes place in a separate header file that is included in a main cpp file, which has the following:
home->input.foo="John";
home->input.bar="Doe";
home->input.name="1234";
printAll(home);
This is were the error pops up, trying to pass home through the function printAll in the header file:
void printAll(node* start){
if(start==NULL) return;
printAll(start->left);
cout << start->input.foo;
printall(start->right);
}
The error that Visual Studio gives me is 0xCDCDCDCD on start. I understand it's not home that is causing the issue, it's start, but I don't understand how to correct this error. I read around and I can assume that start has been thrown into heap memory but it is unintalized. I didn't think this was possible. And I also can guess that C++ doesn't know what start is and how to use it, how would I correct this?
You haven't initialized left or right. In debug builds, Visual Studio will set uninitialized memory to 0xCDCDCDCD. This is obviously not equal to NULL, so your comparison returns false.
As noted in the other answer, the error you are getting may be because you haven't initialized the left and right node as NULL. However you have another error and that is you have created an infinite loop in your printAll.
Your printAll function will first move to the left-most node and print it. After that it will move one node to the right, and, before prints it anything, it'll move to the left again.
The proper way of printing all the nodes is to put list of nodes within a class that keeps track of the first and last node.
Class LList {
node * startNode;
void printAll(){
if (startNode == NULL)
return;
node * currNode = startNode;
// print all the nodes moving left to right
_printAll(currNode);
}
void _printAll(currNode){
// print currNode and recursively go to next by calling
// _printAll(currNode->right)
}
}
Additional things to note
Of course, you'll want to make printAll public and the rest of the
above private.
You'll also need a function to add a node to the list. Look up linked lists attributes and methods to see what else you'll need.
It's better to avoid structs and use objects in place of them

Destructor causing runtime error

I am working with Trees, for practice purpose. Precisely Binary Search Trees currently. I have a general Tree class which I use to solve the BST problems.
So, I come across a problem tp convert the given tree (BST) into a Doubly linked list.
I am able to successfully convert the tree into a DLL. But, the problem is when I call the destructor.
Since, I am allocating memory to the nodes of my Tree, I also wish to free the memory.
This is the destructor of the Tree class ::
~Tree() {
delete root;
root = NULL;
}
And this is the destructor of the Node class::
~Node() {
delete left;
delete right;
left = NULL;
right = NULL;
}
So, the program crashes at the end!
To my understanding since the destructors that I have written kindof recursively delete all the nodes of the tree, and when the Tree is converted to a DLL, the left and right pointers indeed point to each other, so, during the call to the destructor, the destructor tries to delete the node which has already been deleted and that pointer has not been set to NULL.
How do I overcome this? Since destructor overloading is not permitted.
Is there any way I could prevent this runtime error??
This is the code :: http://ideone.com/SDkXY9
(Ideone doesn't print the output, I don't know why!)
The problem here is that you are trying to delete neighbours from whom the chained destruction is initiated. You will have to add a flag which you can check in the destructor for which neighbour is sane to delete.
~Node() {
_isDestructing = true;
if (!left->_isDestructing) delete left;
if (!right->_isDestructing) delete right;
left = NULL;
right = NULL;
}

Geting Data from a Tree Structure

I have a tree structure that i am creating the following way. The tree is created correctly as far as i know. But when i want to get the data from a node, i get some weird acsii symbols.
How I set the data.Lets say its empty. Doesn't matter at the moment. I have a value in my program. The function feeds itself until i get to the end of the data.
struct Node {
char Data;
Node* Left;
Node* Right;
};
Node maketree(0,s,split)
{
Node node;
node.Data=' ';
Node n1=subsplit(0,s,splitingat);
Node n2= subsplit(1,splitingat+1,e);
node.Left=&n1;
node.Right=&n2;
return node;
}
This is how i get data from the tree.
char decode(Node node,string text)
{
int currentindex=0;
Node sub=node;
{
}
if(text[currentindex]=='0')
{
sub=*sub.Left;
cout<<" x "<<sub.Data<<endl;
}
else if(text[currentindex]=='1')
{
sub=*sub.Right;
cout<<" x "<<sub.Data<<endl;
}
// cout<<sub.Data<<endl;
}
I think that the mistake is that I am printing out the pointer and not the node. But I don't know where I went wrong.
The source of your problem appears to be here:
Node node;
node.Data=' ';
Node n1=subsplit(0,s,splitingat);
Node n2= subsplit(1,splitingat+1,e);
node.Left=&n1; // danger Will Robinson!
node.Right=&n2;
return node;
You're taking the addresses of local, temporary, automatic variables and storing them in pointers that you return through node. As soon as that return executes, n1 and n2 are destroyed and node.Left and node.Right are left pointing to garbage. You may be able to fix this like so:
Node* n1=new Node(subsplit(0,s,splitingat));
Node* n2=new Node(subsplit(1,splitingat+1,e));
// side note: probably better to have subsplit() return dynamically-allocated Node*s to avoid the copy
node.Left=n1;
node.Right=n2;
but you may still have issues crop up if similar things are being done elsewhere.
Kind of along the same lines, in your second block of code, you are making a copy of each node you examine and storing it into sub. It would probably make more sense to have sub be a Node*.
And finally, to avoid memory management issues (almost) altogether, use shared_ptr<Node> instead of Node* in all of the above. :)

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.

Exception free tree destruction in C++

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)
}