0

I'm trying to write a binary tree to a file using a recursive function. The call to writeFile(std::string fileName) opens the file stream and then passes it to the recursive function call, writeFile(BinNode<T> ptr, std::ofstream outFile). The compiler comes back with the error "attempting to reference a deleted function" when the first function calls the second function (line noted in my code. I researched the error code and I have a default constructor, a destructor so none of the functions are implicit. Any ideas would be greatly appreciated.

BinTree.h:

#ifndef BINTREE_H
#define BINTREE_H

#include <iostream>
#include <fstream>
#include "BinNode.h"

template<typename T>
class BinTree {
public:
    BinTree(); // Default constructor
    // Value semantics
    // copy constructor
    BinTree(const BinTree<T>& source);
    // assignment operator
    BinTree<T>& operator=(const BinTree<T>& source);
    // destructor
    ~BinTree() { free(root); }

    bool isEmpty();
    void add(T item);
    void printAll() { print(root); }
    bool readFile(std::string fileName);
    bool writeFile(std::string fileName);

private:
    BinNode<T>* root;
    void free(BinNode<T>* ptr);
    void print(BinNode<T>* ptr);
    void copyTree(BinNode<T>* ptr);
    void writeFile(BinNode<T>* ptr, std::ofstream outFile);
};

#include "BinTree.template"
#endif

BinTree.template:

#include "BinTree.h"
// BinTree.template definition

template <typename T>
BinTree<T>::BinTree() {
    root = nullptr;
}

template<typename T>
BinTree<T>::BinTree(const BinTree<T>& source) {
    this->root = nullptr;
    copyTree(source->root);
}

template<typename T>
BinTree<T>& BinTree<T>::operator=(const BinTree<T>& source) {
    if (this == &source)
        return *this;
    free(this->root);
    this->root = nullptr;
    copyTree(source->root);
}

template<typename T>
bool BinTree<T>::isEmpty() {
    return (root == nullptr);  // true - empty, false - not empty
}

template<typename T>
void BinTree<T>::add(T item) {
    BinNode<T>* temp = new BinNode<T>(item);  // other constructor

    if (isEmpty())
        root = temp;
    else {
        BinNode<T>* ptr = root;
        while (ptr != nullptr) {
            if (temp->data <= ptr->data) {      // Left side
                if (ptr->left == nullptr) {     // Left spot open
                    ptr->left = temp;           // Add it
                    ptr = nullptr;              // End Loop
                }
                else {                          // Left spot not open
                    ptr = ptr->left;
                }
            }
            else {                              // Right side
                if (ptr->right == nullptr) {    // Right open
                    ptr->right = temp;          // Add it
                    ptr = nullptr;              // End Loop
                }
                else {
                    ptr = ptr->right;
                }
            }
        }
    }

}

template<typename T>
bool BinTree<T>::readFile(std::string fileName) {
    std::ifstream inFS;
    inFS.open(fileName);
    T temp;
    if (!inFS.is_open()) {
        std::cout << "Error opening " << fileName << std::endl;
        return false;
    }

    while (!inFS.eof()) {
        getline(inFS, temp);
        add(temp);
    }

    inFS.close();

    return true;
}

template<typename T>
bool BinTree<T>::writeFile(std::string fileName) {
    std::ofstream outFS;
    outFS.open(fileName);
    if (!outFS.is_open()) {
        std::cout << "Error writing to " << fileName << std::endl;
        return false;
    }

    writeFile(root, outFS);  // <------ COMPILER ERROR ON THIS LINE ****

    outFS.close();

    return true;
}

template<typename T>
void BinTree<T>::writeFile(BinNode<T>* ptr, std::ofstream outFile) {
    if (ptr != nullptr) {
        writeFile(ptr->left, outFile);
        outFile << ptr->data << std::endl;
        writeFile(ptr->right, outFile);
    }
}

template<typename T>
void BinTree<T>::free(BinNode<T>* ptr) {
    if (ptr != nullptr) {
        free(ptr->left);
        free(ptr->right);
        delete ptr;
    }
}

template<typename T>
void BinTree<T>::print(BinNode<T>* ptr) {
    if (ptr != nullptr) {
        print(ptr->left);
        std::cout << ptr->data << std::endl;
        print(ptr->right);
    }
}

template<typename T>
void BinTree<T>::copyTree(BinNode<T>* ptr) {
    if (ptr != nullptr) {
        add(ptr->data);
        copyTree(ptr->left);
        copyTree(ptr->right);
    }
}

BinNode.h:

#ifndef BINNODE_H
#define BINNODE_H

template <typename T>
class BinTree;

template <typename T>
class BinNode {
    friend class BinTree<T>;
public:
    BinNode() : left(nullptr), right(nullptr), data(T()) {} // Default constructor
    BinNode(T item) : left(nullptr), right(nullptr), data(item) {}

private:
    BinNode<T>* left;
    BinNode<T>* right;
    T data;

};

#endif
Kurt
  • 3
  • 3
  • Recommendation: lose the `#include "BinTree.h"` in BinTree.template. It sets you up for an unnecessary circular dependency. – user4581301 Dec 01 '21 at 23:13
  • When I compile the given code I get a different error: *undefined reference to `main'* – user4581301 Dec 01 '21 at 23:15
  • SUGGESTIONS: 1) See if any of the responses in this thread help: https://stackoverflow.com/a/37517125/421195 2) Q: Exactly which line is giving the compile error? The line in BinTree.h? 3) Is there any reason you can't make "BinTree.template" a normal .cpp file, and eliminate the #include "BinTree.template" from your .h file? – paulsm4 Dec 01 '21 at 23:15
  • 1
    "`free`" is a very unfortunate name for a class method that does what this one does. Also: this question's shown code fails to meet Stackoverflow's requirements for showing a [mre]. Because of that it's unlikely that anyone here can conclusively answer the question. You need to [edit] your question to show a minimal example, no more than one or two pages of code (the "minimal" part), that everyone else can cut/paste ***exactly as shown***, compile, run, and reproduce the described issue (the "reproducible" part, this includes any ancillary information, like any input to the program). – Sam Varshavchik Dec 01 '21 at 23:19
  • 3
    `std::ofstream` isn't copyable. Take it by reference - `void writeFile(BinNode* ptr, std::ofstream& outFile);`. – Mike Vine Dec 01 '21 at 23:19
  • My main function is in a separate .ccp file that uses these files. – Kurt Dec 01 '21 at 23:20
  • Thank you, it was because I wasn't passing the reference to the ofstream. Thanks Mike! – Kurt Dec 01 '21 at 23:23

1 Answers1

3

Your function gets the std::ofstream by value, but the copy constructor is deleted: You need to pass the stream by reference instead:

template<typename T>
void BinTree<T>::writeFile(BinNode<T>* ptr, std::ofstream &outFile) {
    // ...
}
Dmitry Kuzminov
  • 6,180
  • 6
  • 18
  • 40