c++treedestructorpostorder

Exception thrown when calling the destructor on postOrderDeletion


The goal of the program is to create an object call Product and add that product object to the tree object. Once you add six or seven products, the main function needs to call the destructor (.~BinarySearchTree()) to delete all products by implementing a post order deletion functon. When I run the program, it throws an exception (read access violation). The implementation of the ~BinarySearchTree() and postOrderDeletion is in BinarySearchTree.cpp

I tried deleting the product by implementing a regular method, but that didn't work. I tried deleting the product one by one: it worked, but the program needs to implementing a post order deletion method.

proudct.h

#include <iostream>

#ifndef PRODUCT_H
#define PRODUCT_H
class Product
{
public:
    Product(); // Defaul Constructor
    Product(std::string name, int numberOfItem, double price);
    //Constructor

// Declaring getters
std::string getName() const;
int getNumberOfItem() const;
double getPrice() const;

// Declaring setters
void setName(std::string name);
void setNumberOfItem(int numberOfItem);
void setPrice(double price);

//Utility function
friend std::ostream& operator << (std::ostream& out, const Product& e);
void print();

// Private data members
    private:
    std::string name;
    int numberOfItem;
    double price;
    };
#endif

product.cpp

#include <iostream>
#include "Product.h"

Product::Product() // implementing default constructor
{
    setName("N/A");
    setNumberOfItem(0);
    setPrice(0.0);
}

Product::Product(std::string name, int numberOfItem, double price) // implementing constructor
{
    setName(name);
    setNumberOfItem(numberOfItem);
    setPrice(price);
}

void Product::setName(std::string name) // setting name to this instance
{
    this->name = name;
}

void Product::setNumberOfItem(int numberOfItem) // setting number of items to this instance
{
    this->numberOfItem = numberOfItem;
}

void Product::setPrice(double price) // setting price to this instance
{
    this->price = price;
}

std::string Product::getName() const // returning name of this instance
{
    return name;
}

int Product::getNumberOfItem() const // returning number of item of this instance
{
    return numberOfItem;
}

double Product::getPrice() const // returning price of this instance
{
    return price;
}

Node.h

#include "Product.h"
#ifndef NODE_H
#define NODE_H
class Node
{
public:
    Node()
    {
        left = NULL;
        right = NULL;
    }
private:
    Node* left; // node pointer to left of node
    Node* right; // node pointer to right of node
    Product data; // the product data

    // The binary search tree class can have access to private data members
    friend class BinarySearchTree;
};
#endif // NODE_H

BinarySearchTree.h

#include "Node.h"
#include "Product.h"

#ifndef BINARY_SEARCH_TREE_H
#define BINARY_SEARCH_TREE_H
class BinarySearchTree
{
public:
    BinarySearchTree();
    ~BinarySearchTree();

    void addNode(const Product theProduct);
    void addNode(Node* node, const Product theProduct);

    void postOrderDeletion(Node* node);

    bool isRootEmpty() const;

    //void test();
private:
    Node* root;
};
#endif //BINARY_SEARCH_TREE_H

BinarySearchTree.cpp

#include <iostream>

#include "BinarySearchTree.h"

BinarySearchTree::BinarySearchTree()
{
    root = NULL;
}

BinarySearchTree::~BinarySearchTree()
{
    postOrderDeletion(root);
}

void BinarySearchTree::addNode(const Product theProduct)
{
    if (isRootEmpty())
    {
        Node* newNode = new Node();
        newNode->data = theProduct;
        root = newNode;
    }
    else
    {
        addNode(root, theProduct);
    }

}

void BinarySearchTree::addNode(Node* node, const Product theProduct)
{
    if (theProduct.getName() <= node->data.getName())
    {
        if (node->left)
        {
            addNode(node->left, theProduct);
        }
        else
        {
            Node* newNode = new Node();
            newNode->data = theProduct;
            node->left = newNode;
        }
    }
    else
    {
        if (node->right)
        {
            addNode(node->right, theProduct);
        }
        else
        {
            Node* newNode = new Node();
            newNode->data = theProduct;
            node->right = newNode;
        }
    }
}

void BinarySearchTree::postOrderDeletion(Node* node)
{
    if (node)
    {
        postOrderDeletion(node->left);
        postOrderDeletion(node->right);
        delete node;
    }
}

bool BinarySearchTree::isRootEmpty() const
{
    return (root == NULL);
}

Main.cpp

#include <iostream>

#include "BinarySearchTree.h"

int main()
{
    BinarySearchTree bst;

    Product product1("Napkins", 5, 1.99);
    Product product2("Paper", 10, 0.50);
    Product product3("Chips", 2, 3.45);
    Product product4("Diapers", 10, 7.25);
    Product product5("Video Games", 50, 60.79);
    Product product6("Books", 100, 15.45);
    Product product7("Pens", 123, 4.99);
    Product product8("Pencils", 234, 1.99);
    Product product9("Notebook", 10000, 4.55);
    Product product10("Compositon Notebook", 5000, 2.99);
    Product product11("Cake", 50, 25.00);

    bst.addNode(product5);
    bst.addNode(product9);
    bst.addNode(product3);
    bst.addNode(product7);
    bst.addNode(product8);

    bst.~BinarySearchTree();
    //bst.test();

    return 0;
}

Solution

  • Don't do this: bst.~BinarySearchTree(); - just let bst go out of scope and the destructor will be called automaticallly. As it is, it will now be called twice and boom.

    If you want to delete all nodes in the tree without destroying the BinarySearchTree object itself, add a public clear() method.

    class BinarySearchTree
    {
    public:
        //...
        void clear();
        //...
    };
    
    void BinarySearchTree::clear() {
        postOrderDeletion(root);
    }
    
    BinarySearchTree::~BinarySearchTree()
    {
        clear(); // use the new clear() method
    }
    

    Then try this:

    #include <iostream>
    #include "BinarySearchTree.h"
    
    int main()
    {
        { // extra test scope added
    
            BinarySearchTree bst;
    
            // add your product nodes
            // and DONT do bst.~BinarySearchTree();
    
            bst.clear();
    
            // add new nodes here
    
        } // calls the destructor that calls clear() and then frees memory here
    
        std::cout << "still alive\n";
    
        // or with dynamically allocated objects:
        auto bst = new BinarySearchTree;
        // use it
        delete bst; // calls the destructor and frees memory here
    
        std::cout << "still alive\n";
    }