Memory leak in assignment operator for binary search tree - c++

So I can't seem to find out why I'm leaking memory, can anyone help? I've implemented a binary search tree with operator=:
BinTree& BinTree::operator=(const BinTree &other)
{
if (other.root == NULL)
root = NULL;
else
{
copyHelper(root, other.root);
}
return *this;
}
copyHelper:
void BinTree::copyHelper(Node *&current, const Node *other)
{
if (other == NULL)
current = NULL;
else
{
current = new Node;
current->data = other->data;
copyHelper(current->left, other->left);
copyHelper(current->right, other->right);
}
}
I understand that current = new Node; is where the leak is happening, but my program crashes if I try to do delete current; before that line.
Here is my destructor:
BinTree::~BinTree()
{
destroyRecursive(root);
}
void BinTree::destroyRecursive(Node *node)
{
if (node)
{
destroyRecursive(node->left);
destroyRecursive(node->right);
delete node;
}
}

Since you use raw pointers you must delete allocated memory manually. You leak memory when you set current to NULL
void BinTree::copyHelper(Node *&current, const Node *other)
{
if (other == NULL)
{
delete current; // w/o this line next
current = NULL; // will cause memory leak (if not managed somewhere else)
}
else
{
current = new Node;
current->data = other->data;
copyHelper(current->left, other->left);
copyHelper(current->right, other->right);
}
}

Poor code structure. C++ gives you every facility for doing this, yet you're taking little or no advantage of it. You need to delete the root of the current tree, in the operator function, and then copy-construct the new nodes; and you need to fix your destructors.
The recursive copy helper should be a copy constructor in the Node class:
Node::Node(const Node &other) : left(0), right(0)
{
this->data = other.data; // This must be a deep copy
if (other.left)
this->left = new Node(other.left);
if (other.right)
this->right = new Node(other.right);
}
This is called by the BinTree assignment operator:
BinTree& BinTree::operator=(const BinTree &other)
{
delete root;
this->root = 0;
if (other.root)
this->root = new Node(other.root);
return *this;
}
You don't need the recursive destroy method. All you need in the BinTree destructor is delete root;, and a destructor for Node:
Node::~Node()
{
delete left;
delete right;
}
The copying of data must be a deep copy. For example, if it's a C string, use strdup(), and free() it in the destructor for Node. If it's a class, that class must have an assignment operator.
As a matter of fact you don't need two classes. Every node is a tree. So you just need a BinTree class.

Related

Read access violation when trying to create copy constructor for linked list

I am having an issue in regards with my linkedlist implementation, where I am trying to create a copy constructor.
// Copy Constructor
List342(const List342& source)
{
*this = source;
}
List342& operator=(const List342& source)
{
Node<T>* s_node = nullptr; // Source node
Node<T>* d_node = nullptr; // Destination node
if (this == &source)
{
return *this;
}
// Empty memory on destination
DeleteList();
// If the source is empty, return the current object.
if (source.head_ == nullptr)
{
return *this;
}
// Copy source node to destination node, then make destination node the head.
d_node = new Node<T>;
d_node->data = (source.head_)->data;
head_ = d_node;
s_node = (source.head_)->next;
// Loop and copy the nodes from source
while (s_node != nullptr)
{
d_node->next = new Node<T>;
d_node = d_node-> next;
d_node->data = s_node->data;
s_node = s_node->next;
}
return *this;
}
For some reason, VS Studio throws a read access violation at me on the line d_node->data = s_node->data despite the while loop trying to prevent this.
The culprit may be lying in DeleteList, but for some reason my other methods, like printing the linkedlist, have no issues after calling DeleteList, as it prints nothing. I'm just wondering if there's any flaws in this DeleteList method.
// Delete all elements in the linked list
// Not only do you need to delete your nodes,
// But because the Node data is a pointer, this must be deleted too
void DeleteList()
{
// Similar to the linkedlist stack pop method except you're running a while
// loop until you the is empty.
Node<T>* temp;
while (head_ != nullptr)
{
temp = head_;
head_ = head_->next;
// For some reason if I try to delete temp->data, I keep getting symbols not loaded or debug
// assertion errors
// delete temp->data;
// What I can do here is set it to null
// Then delete it. This may have to do how uninitialized variables have random memory assigned
temp->data = nullptr;
delete temp->data;
delete temp;
}
}
Here is the Node definition:
template <class T>
struct Node
{
T* data;
//string* data;
Node* next;
}
By having Node::data be declared as a pointer, your code is responsible for following the Rule of 3/5/0 to manage the data pointers properly. But it is not doing so. Your copy assignment operator is shallow-copying the pointers themselves, not deep-copying the objects they point at.
Thus, DeleteList() crashes on the delete temp->data; statement, because you end up with multiple Nodes pointing at the same objects in memory, breaking unique ownership semantics. When one Node is destroyed, deleting its data object, any other Node that was copied from it is now left with a dangling pointer to invalid memory.
If you must use a pointer for Node::data, then you need to copy-construct every data object individually using new so DeleteList() can later delete them individually, eg:
d_node = new Node<T>;
d_node->data = new T(*(source.head_->data)); // <--
...
d_node->next = new Node<T>;
d_node = d_node->next;
d_node->data = new T(*(s_node->data)); // <--
...
However, this is no longer needed if you simply make Node::data not be a pointer in the first place:
template <class T>
struct Node
{
T data; //string data;
Node* next;
}
That being said, your copy constructor is calling your copy assignment operator, but the head_ member has not been initialized yet (unless it is and you simply didn't show that). Calling DeleteList() on an invalid list is undefined behavior. It would be safer to implement the assignment operator using the copy constructor (the so-called copy-swap idiom) , not the other way around, eg:
// Copy Constructor
List342(const List342& source)
: head_(nullptr)
{
Node<T>* s_node = source.head_;
Node<T>** d_node = &head_;
while (s_node)
{
*d_node = new Node<T>;
(*d_node)->data = new T(*(s_node->data));
// or: (*d_node)->data = s_node->data;
// if data is not a pointer anymore...
s_node = s_node->next;
d_node = &((*d_node)->next);
}
}
List342& operator=(const List342& source)
{
if (this != &source)
{
List342 temp(source);
std::swap(head_, temp.head_);
}
return *this;
}
However, the copy constructor you have shown can be made to work safely if you make sure to initialize head_ to nullptr before calling operator=, eg:
// Copy Constructor
List342(const List342& source)
: head_(nullptr) // <--
{
*this = source;
}
Or:
// Default Constructor
List342()
: head_(nullptr) // <--
{
}
// Copy Constructor
List342(const List342& source)
: List342() // <--
{
*this = source;
}
Or, initialize head_ directly in the class declaration, not in the constructor at all:
template<typename T>
class List342
{
...
private:
Node<T> *head_ = nullptr; // <--
...
};

Binary Search Tree Destructor issue

I am currently making a code a class code for binary search tree but I am getting an error in the destructor for my BST class. This is my relevant part of code:
Node Struct:
struct Node{
int key;
struct Node* left;
struct Node* right;
};
Function to Create new node:
Node* BST::CreateNode(int key){
Node* temp_node = new Node();
temp_node->key = key;
temp_node->left = nullptr;
temp_node->right = nullptr;
return temp_node;
}
Assignment Operator:
BST& BST::operator=(const BST& cpy_bst){
if (this != &cpy_bst){
Node* cpy_root = cpy_bst.root;
this->root=assgRec(cpy_root, this->root);
}
return *this;
}
Node* BST::assgRec(Node* src_root, Node* dest_root){
if (src_root != nullptr){
dest_root = CreateNode(src_root->key);
dest_root->left=assgRec(src_root->left, dest_root->left);
dest_root->right=assgRec(src_root->right, dest_root->right);
}
return src_root;
}
Destructor:
BST::~BST(){
DestroyNode(root);
}
void BST::DestroyNode(Node* r){
if (r != nullptr){
DestroyNode(r->left);
DestroyNode(r->right);
delete r;
}
}
The problem is that after I have used the assignment in main function, like:
BST bin_tree2=bin_tree1;
The destructor is called but after it deletes the data in bin_tree1, all values that were placed in bin_tree2 have some junk values in them and I get an error on that part. Any help would be greatly appreciated. Thanks
This looks like you are copying pointers and accessing them after memory has been deallocated.
The problem seems not to be with the keys as I said earlier but with the nodes that seem to be improperly constructed in the BST::assgRec function.

Nodes added to linked list revert back to NULL after function

I'm reading lines from a file and storing them into linked list.
void add(llist *list, somevalue) {
Node *newnode = (Node *) malloc(sizeof(Node));
newnode->value = somevalue;
newnode->next = list->head;
list->head = newnode;
}
and I call this function from an initialize function which opens the file and reads lines from the file.
void init() {
llist *list = (llist *) malloc(sizeof(llist));
//
//bunch of file i/o codes
//
while (read file until it returns NULL) {
add(list, line);
//if I try to print the values of the list here it works.
}
//Outside the loop, the head is back to NULL
}
And another problem that I realized is the values get concatenated every time I try to print the value. That is to say, the output would be:
First Loop: Tony
Second Loop: Peter
TonyPeter
Third Loop: Mir
PeterMir
TonyPeterMir
How do I fix it so the add function permanently adds the node to the linked list?
Why would the values be jumbled up like that?
----EDITED----
The list is a global variable, and here are some more snippets from the init function. This is the while loop with the problem:
//open file
//initialize & declare pointers
while (1) {
for (i = 0; i < max; i++) {
value[i] = '\0';
}
if (!(fgets(value,max,f))) {
//segfaults if I try to print out the list inside this block.
break;
}
add(list, value);
//the values are well separated in this statement
printf("id is %s\n", list->head->value);
//This print list works, but works weird as shown above.
print_list(list);
}
fclose(f);
//This print list doesn't work, the list is NULL
print_list(list);
And this is the print list function:
void print_users(llist *list) {
ListNode *e;
if (list->head == NULL) {
printf("NO USERS\r\n");
return;
}
e = list->head;
while (e != NULL) {
puts(e->id);
e = e->next;
}
}
So I don't have a good grasp at all on what you're exactly trying to do here, so we can only do but so much. You may consider posting a MCVE. However, I may be able to give you some pointers on building a linked list. I directly copied your add function into a linked list class that I just hurriedly built, and it worked fine, so there may be something else in your llist class that is causing the issue, or it could be something else in your code. The class and a brief description of the class are listed below.
basic node class
Note: I used templates, but you could just as easily remove the template statements and replace T with any type.
template<typename T>
class node {
private:
T data;
node* next;
public:
// The C++11 rule of 5
// Default Constructor
node(T value = T(), node* nxt = nullptr) : data(value), next(nxt) { }
// Copy Constructor
node(const node<T>& src) : data(src.data), next(src.next) { }
// Move Constructor
node(node<T>&& src) : data(src.data), next(src.next) {
src.data = T();
src.next = nullptr;
}
// Copy Assignment Operator
node<T>& operator=(const node<T>& src) {
this->data = src.data;
this->next = src.next;
return(*this);
}
// Move Assignment Operator
node<T>& operator=(node<T>&& src) {
this->data = src.data;
this->next = src.next;
src.data = T();
src.next = nullptr;
}
// Destructor
~node() {};
// Some functions to help with encapsulation
void set_next(node* nxt) {
this->next = nxt;
}
void set_data(T value) {
this->data = value;
}
node* get_next() {
return(this->next);
}
T& get_data() {
return(data);
}
};
linked list class body
Since you're using dynamic memory, you need to make sure you adhere to the rule of 3 or 5 depending on whether or not you're using C++11.
template<typename T>
class llist {
private:
node<T>* head;
public:
llist();
llist(const llist& src);
llist(llist&& src);
llist(~llist);
llist& operator=(const llist& src);
llist& operator=(llist&& src);
void push();
void insert();
};
default constructor
Nothing fancy here.
template<typename T>
llist<T>::llist() : head(nullptr) { }
copy constructor
Since you're using dynamic memory this is crucial
template<typename T>
llist<T>::llist(const llist& src) {
node<T>* tmp = src.head;
while(tmp) {
this->push(tmp->get_data());
}
}
move constructor
template<typename T>
llist<T>::llist(llist&& src) {
// delete current nodes
node<T>* tmp = this->head;
while(tmp) {
tmp = head->get_next();
delete head;
head = tmp;
}
// steal the sources list
this->head = src.head;
src.head = nullptr;
}
destructor
template<typename T>
llist<T>::~llist() {
node<T>* tmp = this->head;
while(tmp) {
tmp = head->get_next();
delete head;
head = tmp;
}
}
copy assignment operator
template<typename T>
llist& llist<T>::operator=(const llist<T>& src) {
node<T>* tmp = src.head;
while(tmp) {
this->push(tmp->get_data());
}
return(*this);
}
move assignment operator
template<typename T>
llist& llist<T>::operator=(llist<T>&& src) {
node<T>* tmp = this->head;
while(tmp) {
tmp = head->get_next();
delete head;
head = tmp;
}
this->head = src.head;
src.head = nullptr;
return(*this);
}
push member
this is essentially opposite of your add member.
template<typename T>
void llist<T>push(T data) {
node<T>* new_node = new node<T>(data);
if(this->head) {
node<T>* tmp = this->head;
while(tmp->get_next()) {
tmp = tmp->get_next();
}
tmp->set_next(new_node);
} else {
this->head = new_node;
}
}
insert member
This is essentially your add member.
template<typename T>
void llist<T>insert(T data) {
node<T>* new_node = new node<T>(data, this->head);
this->head = new_node;
}
I don't know if this will help, and you probably already have and know most of this, but I hope it helps.
In this code, it would appear that you attempted to 'malloc' space for a "llist" user defined object.
void init() {
llist *list = (llist *) malloc(sizeof(llist));
//
//bunch of file i/o codes
//
while (read file until it returns NULL) {
add(list, line);
//if I try to print the values of the list here it works.
}
//Outside the loop, the head is back to NULL
}
First, you tagged this as C++. In C++, you simply must use new and delete. The C++ compiler does not associate "malloc" with the ctor / dtor of your user created object called "llist". And I assure you that you really do want to create these two methods, even when each are simple. Really.
On the other hand, the C++ compiler does provide New and Delete, and will automatically invoke the ctor and dtor when appropriate for both dynamic variables (in heap), and automatic variables (on stack). The compiler will not support this with malloc.
Second, your function init() does not return or otherwise deliver the value of the automatic variable you named "list" to any other scope. (Typically, a list lifetime exceeds the life of any function that uses or creates it.)
So your object "list" only exists within the scope of the function init(), within the lifetime of init(). Not very useful.
So the handle to the list of 'malloc'ed things is lost, no longer accessible to anything else. After init(), where did you plan for the listHead to reside?
Even if you used new (and delete) the code still does not deliver the listHead anywhere.
To further your program, you need perhaps 1 of 2 things:
1) a return (from the function) of the "list" handle (I've been calling it "listHead" as you intended, right?)
llist* init() {
llist *listHead = ...
return(listHead);
}
OR
2) a parameter reference which your init function changes. This places the list head outside of init().
void init( llist** listHead) {
llist *list = ...
*listHead = list;
}
You might look into, and take hints from std::list, which has 40+ methods, though you might only need 10. For the methods you plan to implement, you should strive to conform to and use similar names and parameters.
Perhaps you meant to use a class data attribute with the label list (it is quite difficult to imagine this from what you provided). In this case, you should distinguish data attributes names to help you remember what it is, and that it has a different scope. For instance, I would use m_listHead. The prefix m_ (or often, simply the one char prefix '_') simply indicates to the reader that this symbol is a data attribute of a class. This idea is a common c++ idiom, and not enforced by the compiler, but is often part of a coding-standard.
Good luck.

Deep Copy Constructor for binary tree

I am trying to create a deep copy of my binary tree data structure in C++. The problem is the code I am using only seems to be giving me a shallow copy (which seems to cause problems with my deconstructor).
the code below is my binary tree copy constructor:
BinaryTreeStorage::BinaryTreeStorage(const BinaryTreeStorage &copytree):root(NULL)
{
root = copytree.root;
copyTree(root);
}
BinaryTreeStorage::node* BinaryTreeStorage::copyTree(node* other)
{
//if node is empty (at bottom of binary tree)
/*
This creates a shallow copy which in turn causes a problem
with the deconstructor, could not work out how to create a
deep copy.
*/
if (other == NULL)
{
return NULL;
}
node* newNode = new node;
if (other ->nodeValue == "")
{
newNode ->nodeValue = "";
}
newNode->left = copyTree(other->left);
newNode->right = copyTree(other->right);
return newNode;
}
Any help would be appreciated.
Thanks
Here is the deconstructor that throws a memory exception (which i believe is because of the shallow copy i do above)
BinaryTreeStorage::~BinaryTreeStorage(void)
{
try
{
destroy_tree();//Call the destroy tree method
delete root;//delete final node
}
catch(int &error)
{
cout << "Error Message : " << error << endl;
}
}
void BinaryTreeStorage::destroy_tree()
{
destroy_tree(root);
}
void BinaryTreeStorage::destroy_tree(node *leaf)
{
if(leaf!=NULL)
{
//Recursively work way to bottom node
destroy_tree(leaf->left);
destroy_tree(leaf->right);
//delete node
delete leaf;
}
}
You're not performing a deep copy of your root node, only its children.
Shouldn't it be:
root = copyTree(copytree.root);
?
EDIT: In addition, you destroy the root twice:
destroy_tree();//Call the destroy tree method
//once here
//remove this line
delete root;//delete final node
and
if(leaf!=NULL)
{
//Recursively work way to bottom node
destroy_tree(leaf->left);
destroy_tree(leaf->right);
//one more time here
delete leaf;
}
If you only do one of these fixes, the problem won't be solved.
Actually, I think we can directly using the copy constructor to recursively deep copy the tree. Suppose the class is defined as follows:
class TreeNode {
public:
TreeNode() : value(), count(0), left(nullptr), right(nullptr) {}
TreeNode(const TreeNode &);
~TreeNode();
TreeNode &operator=(const TreeNode &);
// Other members...
private:
std::string value;
int count;
TreeNode *left;
TreeNode *right;
// Note that the valid state for the `left` and `right` pointer is either
// `nullptr` or a subtree node. So that we must check these pointers every
// time before dereferencing them.
};
Then the copy constructor is
TreeNode::TreeNode(const TreeNode &n)
: value(n.value), count(n.count), left(nullptr), right(nullptr) {
if (n.left)
left = new TreeNode(*n.left); // recursively call copy constructor
if (n.right)
right = new TreeNode(*n.right); // recursively call copy constructor
}
The recursion will be stopped at the leaf node, since both its two children are nullptr.
And so does the destructor.
TreeNode::~TreeNode() {
delete left; // recursively call destructor on left subtree node
delete right; // recursively call destructor on right subtree node
}
When left or right is nullptr, delete will do nothing, so that the recursion will be stopped.
You can see the complete code from here.

List destructor in C++

I've just implemented the Linked List. It works perfectly fine but even tough I've seen notation I am unable to create working destructor on Node, that's why it's unimplemented here in code.
I need to implement working destructor on node
Destructor of List but this one is simple I will just use the destructor from Node class(but I need this one).
Make the List friendly to Node so I will not have to use getNext(), but I think I can
handle it myself(not sure how, but I'll find out).
Please look at the code it is perfectly fine, just will work if you copy it.
#include <cstdio>
#include <cmath>
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
class Node {
public:
Node(Node* next, int wrt) {
this->next = next;
this->wrt = wrt;
}
Node(const Node& obiekt) {
this->wrt = obiekt.wrt;
this->next = obiekt.next;
}
~Node() {}
void show() {
cout << this->wrt << endl;
}
int getWrt(){
return this->wrt;
}
Node* getNext(){
return this->next;
}
void setNext(Node* node){
this->next = node;
}
private:
Node* next;
int wrt;
};
class List{
public:
List(int wrt){
this->root = new Node(NULL, wrt);
}
List(const List& obiekt){
memcpy(&this->root,&obiekt.root,sizeof(int));
Node* el = obiekt.root->getNext();
Node* curr = this->root;
Node* next;
while(el != NULL){
memcpy(&next,&el,sizeof(int));
curr->setNext(next);
curr = next;
next = curr->getNext();
el = el->getNext();
/* curr->show();
next->show();
el->show(); */
}
}
void add(int wrt){
Node* node = new Node(NULL, wrt);
Node* el = this->root;
while(el->getNext() != NULL){
//el->show();
el = el->getNext();
}
el->setNext(node);
}
void remove(int index){
Node* el = this->root;
if(index == 0){
//deleting old one
this->root = this->root->getNext();
}
else{
int i = 0;
while(el != NULL && i < index - 1){
// el->show();
el = el->getNext();
i++;
}
if(el!=NULL){
Node* toRem = el->getNext();
Node* newNext = toRem->getNext();
el->setNext(newNext);
//deleteing old one
}
}
}
void show(){
Node* el = this->root;
while(el != NULL){
el->show();
el = el->getNext();
}
}
~List(){}
private:
Node* root;
};
int main(){
List* l = new List(1); //first list
l->add(2);
l->add(3);
l->show();
cout << endl;
List* lala = new List(*l); //lala is second list created by copy cosntructor
lala->show();
cout << endl;
lala->add(4);
lala->remove(0);
lala->show();
return 0;
}
I suggest you to start with implementing destructor of List. Since you dynamically allocated memory by using new, you should free it by using delete. (If you used new[], it would be delete[]):
~List()
{
Node* currentNode = this->root; // initialize current node to root
while (currentNode)
{
Node* nextNode = currentNode->getNext(); // get next node
delete currentNode; // delete current
currentNode = nextNode; // set current to "old" next
}
}
Once you have proper destructor, you should try whether your copy constructor is correct:
List* lala = new List(*l);
delete l; // delete list that was used to create copy, shouldn't affect copy
you will find out that your copy constructor is wrong and also causes your application to crash. Why? Because purpose of copy constructor is to create a new object as a copy of an existing object. Your copy constructor just copies pointers assuming sizeof(Node*) equal to sizeof(int). It should look like this:
List(const List& list)
{
// if empty list is being copied:
if (!list.root)
{
this->root = NULL;
return;
}
// create new root:
this->root = new Node(NULL, list.root->getWrt());
Node* list_currentNode = list.root;
Node* this_currentNode = this->root;
while (list_currentNode->getNext())
{
// create new successor:
Node* newNode = new Node(NULL, list_currentNode->getNext()->getWrt());
this_currentNode->setNext(newNode);
this_currentNode = this_currentNode->getNext();
list_currentNode = list_currentNode->getNext();
}
}
Also your function remove is wrong since it "removes" reference to some Node but never frees memory where this Node resides. delete should be called in order to free this memory.
"I need to implement working destructor on node" - No, you don't. Node itself doesn't allocate any memory, thus it shouldn't free any memory. Node shouldn't be responsible for destruction of Node* next nor cleaning memory where it's stored. Don't implement destructor nor copy constructor of Node. You also want to read this: What is The Rule of Three?
"Make the List friendly to Node so I will not have to use getNext()" - You want to say within Node class, that class List is its friend:
class Node
{
friend class List; // <-- that's it
Note that from these 5 headers that you include your code requires only one: <iostream>.
Also note that writing using namespace std; at the beginning of the file is considered bad practice since it may cause names of some of your types become ambiguous. Use it wisely within small scopes or use std:: prefix instead.
The linked list destructor will be called either when delete is used with a previously allocated pointer to a linked list or when a linked list variable goes out of scope (e.g., a local variable is destroyed when returning from a function).
The destructor for the linked list should be responsible to free the memory you previously reserved for the nodes (i.e., using add operation). So, basically, you need to traverse the list of nodes and apply the delete operation on each one of them. There is a little trick: when you are about to delete a node you must be careful not to lose the pointer to the next element (when a node is deleted you cannot be sure that next member will still be valid).
If you want to create a destructor for your Node, it should be quite simple actually.
Here it is:
class Node {
private:
int wrt;
Node* next;
public:
Node(Node* next, int wrt) {
this->next = next;
this->wrt = wrt;
}
// Your desired destructor using recursion
~Node() {
if ( next != NULL )
delete next;
}
};
It's that simple :)
Basically, right before the Node is deleted, if next is not empty, we delete next, which will again call the destructor of next, and if next->next is not empty, again the destructor gets called over and over.
Then in the end all Nodes get deleted.
The recursion takes care of the whole thing :)