I implemented code logic provided in the EPI book to determine if a binary tree is a BST. There were two approaches, therefore I used polymorphism for the common parts. I'm also using templates. I would appreciate code review on my use of smart pointers? Anything that I should have been doing that I'm not. I did not defined any destructors, should I?#include <iostream>#include <memory>#include <limits>#include <queue>using namespace std;template <typename T>class BinarySearchNode {public:    unique_ptr<BinarySearchNode<T>> leftChild;    unique_ptr<BinarySearchNode<T>> rightChild;    BinarySearchNode(T pData) : data(pData), leftChild(nullptr), rightChild(nullptr) {}    BinarySearchNode(T pData, unique_ptr<BinarySearchNode<T>> pLeft, unique_ptr<BinarySearchNode<T>> pRight)    : data(pData),leftChild(move(pLeft)), rightChild(move(pRight)) {}    T getData() const { return data; };private:    T data;};template <typename T>class BSTSolution {protected:    virtual bool isBSTValid(unique_ptr<BinarySearchNode<T>> const &node,T min, T max) = 0;public:    bool isBinaryTreeValidBinaryTree(unique_ptr<BinarySearchNode<T>> const &root){        if(root == nullptr)            return false;        return isBSTValid(root, numeric_limits<T>::min(), numeric_limits<T>::max());    }};template <typename T>class BSTRecursiveSolution : public BSTSolution<T> {protected:    bool isBSTValid(unique_ptr<BinarySearchNode<T>> const &node,T min, T max) {        if(node == nullptr)        {            return true;        };        if(node->getData() < min || node->getData() > max) {            return false;        }        if(!isBSTValid(node->leftChild, min, node->getData()) || !isBSTValid(node->rightChild, node->getData(), max))        {            return false;        }        return true;    }};template<typename T>class BFSSolution : public BSTSolution<T> {    struct QEntry {        const unique_ptr<BinarySearchNode<T>>& node;        T min;        T max;    };protected:    bool isBSTValid(unique_ptr<BinarySearchNode<T>> const &node,T min, T max) {        queue<QEntry> tempQueue;        tempQueue.emplace(QEntry{node,min,max});        while (!tempQueue.empty()) {            auto const current = tempQueue.front();            if(current.node != nullptr) {                if(current.node->getData() < current.min || current.node->getData() > current.max) {                    return false;                }                tempQueue.emplace(QEntry{current.node->leftChild,current.min,current.node->getData()});                tempQueue.emplace(QEntry{current.node->rightChild,current.node->getData(),current.max});            }            tempQueue.pop();        }        return true;    }};int main(int argc, const char * argv[]) {    unique_ptr<BinarySearchNode<int>> a(new BinarySearchNode<int>(10));    unique_ptr<BinarySearchNode<int>> b(new BinarySearchNode<int>(20));    unique_ptr<BinarySearchNode<int>> root(new BinarySearchNode<int>(15, move(a),move(b)));    root->leftChild->leftChild = std::make_unique<BinarySearchNode<int>>(8);    root->leftChild->rightChild = std::make_unique<BinarySearchNode<int>>(13);    root->rightChild->leftChild = std::make_unique<BinarySearchNode<int>>(18);    root->rightChild->rightChild = std::make_unique<BinarySearchNode<int>>(21);    cout << root->getData() << \n;    BSTRecursiveSolution<int> rSol;    bool valid = rSol.isBinaryTreeValidBinaryTree(root);    cout << is binary tree valid?  << (valid ? YES :)  : NO :() << \n;    BFSSolution<int> bfsSol;    valid = bfsSol.isBinaryTreeValidBinaryTree(root);    cout << is binary tree valid?  << (valid ? YES :)  : NO :() << \n;    return 0;}
Test if a binary tree satisfies the BST property
c++;tree;template;pointers