First Attempt of Edit:
#ifndef BinaryTree_h
#define BinaryTree_h
#include <iostream>
template <class T>
class BinaryTree {
private:
struct TreeNode {
T data;
std::unique_ptr<TreeNode> left = nullptr;
std::unique_ptr<TreeNode> right = nullptr;
TreeNode(T x): data(x){}
};
std::unique_ptr<TreeNode> root = nullptr;
// This is used to free the memory
void deleteTree(std::unique_ptr<TreeNode> &node) {
if(node.get() == nullptr) {
return;
}
deleteTree(node.get()->left);
deleteTree(node.get()->right);
delete node.get();
}
// This is used for the copy constructor
void copyTree(std::unique_ptr<TreeNode> &thisRoot, std::unique_ptr<TreeNode> &sourceRoot) {
if(sourceRoot.get() == nullptr) {
thisRoot.get() = nullptr;
}
else {
thisRoot.get() = new TreeNode{sourceRoot->data};
copyTree(thisRoot->left, thisRoot->left);
copyTree(thisRoot->right, thisRoot->right);
}
}
// These functions are for creating the nodes inside the tree
void insertPrivate(std::unique_ptr<TreeNode> &root, const T &theData);
void insertPrivate(std::unique_ptr<TreeNode> &root, T &&theData);
// Traversal functions for printing the nodes
void inorderTraversal(std::unique_ptr<TreeNode> &root);
void pretorderTraversal(std::unique_ptr<TreeNode> &root);
void postorderTraversal(std::unique_ptr<TreeNode> &root);
public:
// Constructors
BinaryTree() = default; // empty constructor
BinaryTree(BinaryTree const &other){copyTree(root, other.root);} // copy constructor
// Rule of 5
BinaryTree(BinaryTree &&move) noexcept; // move constuctor
BinaryTree& operator=(BinaryTree &&move) noexcept; // move assignment operator
~BinaryTree(); // destructor
// Overload operators
BinaryTree& operator=(BinaryTree const &rhs);
// Member functions
void insert(const T &theData);
void insert(T &&theData);
void printInorder();
void printPreorder();
void printPostorder();
void swap(BinaryTree& other) noexcept;
};
template <class T>
BinaryTree<T>::BinaryTree(BinaryTree &&move) noexcept {
move.swap(*this);
}
template <class T>
BinaryTree<T>& BinaryTree<T>::operator=(BinaryTree &&move) noexcept {
move.swap(*this);
return *this;
}
template <class T>
BinaryTree<T>::~BinaryTree() {
deleteTree(root);
}
template <class T>
BinaryTree<T>& BinaryTree<T>::operator=(BinaryTree const &rhs) {
BinaryTree copy(rhs);
swap(copy);
return *this;
}
template <class T>
void BinaryTree<T>::insertPrivate(std::unique_ptr<TreeNode> &root, const T &theData) {
if(root.get() == nullptr) {
root.get()->data = theData;
return;
}
else if(theData < root.get()->data) {
insertPrivate(root.get()->left, theData);
}
else {
insertPrivate(root.get()->right, theData);
}
}
template <class T>
void BinaryTree<T>::insertPrivate(std::unique_ptr<TreeNode> &root, T &&theData) {
std::cout << "Using with move" << std::endl;
if(root.get() == nullptr) {
root.get() = std::move(theData);
return;
}
else if(theData < root.get()->data) {
insertPrivate(root.get()->left, std::move(theData));
}
else {
insertPrivate(root.get()->right, std::move(theData));
}
}
template <class T>
void BinaryTree<T>::insert(const T &theData) {
insertPrivate(root, theData);
}
template <class T>
void BinaryTree<T>::insert(T &&theData) {
insertPrivate(root, theData);
}
template <class T>
void BinaryTree<T>::inorderTraversal(std::unique_ptr<TreeNode> &root) {
// The items in the left subtree are printed first, followed
// by the item in the root node, followed by the items in
// the right subtree.
if(root.get() != nullptr) {
inorderTraversal(root.get()->left);
std::cout << root.get()->data << " ";
inorderTraversal(root.get()->right);
}
}
template <class T>
void BinaryTree<T>::pretorderTraversal(std::unique_ptr<TreeNode> &root) {
// Print all the items in the tree to which root points.
// The item in the root is printed first, followed by the
// items in the left subtree and then the items in the
// right subtree.
if(root.get() != nullptr) {
std::cout << root.get()->data << " ";
pretorderTraversal(root.get()->left);
pretorderTraversal(root.get()->right);
}
}
template <class T>
void BinaryTree<T>::postorderTraversal(std::unique_ptr<TreeNode> &root) {
// Print all the items in the tree to which root points.
// The items in the left subtree are printed first, followed
// by the items in the right subtree and then the item in the
// root node.
if(root.get() != nullptr) {
postorderTraversal(root.get()->left);
postorderTraversal(root.get()->right);
std::cout << root.get()->data << " ";
}
}
template <class T>
void BinaryTree<T>::printInorder() {
inorderTraversal(root);
}
template <class T>
void BinaryTree<T>::printPreorder() {
pretorderTraversal(root);
}
template <class T>
void BinaryTree<T>::printPostorder() {
postorderTraversal(root);
}
template <class T>
void BinaryTree<T>::swap(BinaryTree &other) noexcept {
using std::swap;
swap(root, other.root);
}
#endif /* BinaryTree_h */