ynimous
ynimous

Reputation: 5142

Building tree with a parent pointer using C++ smart pointers

I'm trying to build a binary tree with smart pointers, where nodes also include a parent pointer. To do that, I defined the children pointers as shared_ptr and the parent pointers as weak_ptr.

The best I could come up with is the following:

#include <iostream>
#include <memory>

using namespace std;

struct Node;

struct NodeBase {
    int val;

    NodeBase(int v) : val(v) {}

    virtual void add_node_left(shared_ptr<Node> &ptr, int v) = 0;
    virtual void add_node_right(shared_ptr<Node> &ptr, int v) = 0;

    virtual ~NodeBase() {};
};

struct NodePtr {
    shared_ptr<NodeBase> ptr;

    template<typename... Args>
    NodePtr(Args&&... args) : ptr(std::forward<Args>(args)...) {}

    void add_left(int v) {
        shared_ptr<Node> node_ptr = std::static_pointer_cast<Node>(ptr);
        ptr->add_node_left(node_ptr, v);
    }

    void add_right(int v) {
        shared_ptr<Node> node_ptr = std::static_pointer_cast<Node>(ptr);
        ptr->add_node_right(node_ptr, v);
    }
};

struct Node : public NodeBase {
    NodePtr left, right;
    weak_ptr<Node> parent;

    Node(int v) : NodeBase(v), left(nullptr), right(nullptr), parent() {}

    shared_ptr<Node> make_child(shared_ptr<Node> &selfptr, int v) {
        auto child = make_shared<Node>(v);
        child->parent = selfptr;
        return child;
    }

    void virtual add_node_left(shared_ptr<Node> &selfptr, int v) {
        left = make_child(selfptr, v);
    }

    void virtual add_node_right(shared_ptr<Node> &selfptr, int v) {
        right = make_child(selfptr, v);
    }


    virtual ~Node() {};
};

struct Tree {
    NodePtr root;

    Tree() : root(nullptr) {};
    Tree(int val) {
        add_root(val);
    }

    void add_root(int val) {
        root = make_shared<Node>(val);
    }
};

int main() {
    Tree tree;
    tree.add_root(10);
    tree.root.add_left(5);
    tree.root.add_right(12);
}

First of all, is this correct?

Second, I'm not very fond of having to define the NodeBase base class. The reason for it is so I can pass the shared_ptr to add_node_left and add_node_right, needed to create the parent weak_ptr. Is there a way to do this that avoids NodeBase but maintains the same (or similar) interface?

Upvotes: 0

Views: 1783

Answers (1)

Caleth
Caleth

Reputation: 63019

You don't need NodeBase nor NodePtr.

struct Node : std::enable_shared_from_this {
    int val;
    std::shared_ptr<Node> left, right;
    std::weak_ptr<Node> parent;

    Node(int v, std::weak_ptr<Node> p) : val(v), left(), right(), parent(p) {}

    void add_node_left(int v) {
        left = std::make_shared<Node>(v, weak_from_this()); // shared_from_this() pre C++17
    }

    void add_node_right(int v) {
        right = std::make_shared<Node>(v, weak_from_this()); // shared_from_this() pre C++17
    }
};

Upvotes: 2

Related Questions