Writing out a tree of Tnodes with words as values in alphabetical order I'm doing this:


  Consider:

struct Tnode {
    string word;
    int count;
    Tnode* left;
    Tnode* right;
};

  
  Write a function for entering new words into a tree of Tnodes. Write a
  function to write out a tree of Tnodes. Write a function to write out
  a tree of Tnodes with the words in alphabetical order. Modify Tnode so
  that it stores (only) a pointer to an arbitrarily long word stored as
  an array of characters on free store using new. Modify the functions
  to use the new definition of Tnode.


Source

Here is my code for the first part ("write a function to write out a tree of Tnodes with the words in alphabetical order"). Please review this.

Note: I know I only have to write a function, but I'm interested in creating a class. Now I'm not sure if this is good code.

struct Tnode {
    std::string word;
    int count; //I'm not sure what's this for. I assume it's for counting nodes.
    Tnode* left;
    Tnode* right;
};

class TreeNode {
    Tnode* node;

    Tnode* add(Tnode* n, const std::string&amp; word) {
        if (n == nullptr) {
            n = new Tnode{word};
        } else if (word &lt; n-&gt;word) {
            n-&gt;left = add(n-&gt;left, word);
        } else if (word &gt; n-&gt;word) {
            n-&gt;right = add(n-&gt;right, word);
        } else {
            n-&gt;word = word;
        }
        //I have to always check for nullptr because I found out dereferencing a nullptr causes undefined behavior. And I have to asign n-&gt;count back to 1 because I notice it keeps adding.
        n-&gt;count = 1;
        if (n-&gt;left != nullptr) {
            n-&gt;count += n-&gt;left-&gt;count;
        }
        if (n-&gt;right != nullptr) {
            n-&gt;count += n-&gt;right-&gt;count;
        }
        return n;
    }

    void traverse(Tnode* t) { //for testing purposes
        if (t == nullptr) {
            return;
        }
        std::cout &lt;&lt; t-&gt;word &lt;&lt; '\n';
        traverse(t-&gt;left);
        traverse(t-&gt;right);
    }

    void destroy_all(Tnode* t) { //I can't think of a better way to destroy all Tnode objects
        if (t == nullptr) {
            return;
        }
        destroy_all(t-&gt;left);
        destroy_all(t-&gt;right);
        delete t;
    }

public:
    TreeNode() { node = nullptr; } //Is doing this fine? I don't know what default value I would use aside from nullptr because I didn't write a subscripting function to access the nodes
    TreeNode(const std::string&amp; word) :node{new Tnode{word}} { }

    void add(const std::string&amp; word) {
        node = add(node,word);
    }

    void traverse() { //for testing purposes
        traverse(node);
    }

    int get_count() {
        return node-&gt;count;
    }

    ~TreeNode() {
        destroy_all(node);
    }

};


How can I make this code better?
Improvements / details:

Your naming is a bit odd. Tnode is not a very descriptive name. TreeNode seems out of context, as the type is actually the tree itself, not a node. 

I suggest renaming TreeNode to just Tree and Tnode to TreeNode instead.

That count parameter seem to be the child count of a given node. It can be used to determine the height of the tree. It is not implemented properly for this purpose though.

I prefer placing private methods and data at the end of the class declaration. Public data and methods should appear at the top, as this is what users of the interface care about when reading the file. Also, it is better to separate the class in declaration and definition. The declaration usually goes in a header file (.h/.hpp).

Wouldn't be a bad idea renaming the recursive helper methods of the tree to make the use of recursion more explicit. You could append _recursive to the name. E.g.: traverse() => traverse_recursive().

Tnode should have a formal constructor to properly initialize its data.

Refactored code:

I took the liberty of applying these changes to your code. Following is the result:

// tree.h:

struct TreeNode {

    std::string word;
    int numChildren;

    TreeNode* left;
    TreeNode* right;

    TreeNode(const std::string&amp; word)
        : word(word), numChildren(0), left(nullptr), right(nullptr) { }
};

class Tree {

public:

    Tree();
    Tree(const std::string&amp; word);

    void add(const std::string&amp; word);
    void traverse();
    int get_num_nodes() const;

    ~Tree();

private:

    TreeNode* add_recursive(TreeNode* n, const std::string&amp; word);
    void traverse_recursive(TreeNode* n);
    void destroy_recursive(TreeNode* n);

    TreeNode * root;
};

// tree.cpp:

Tree::Tree()
    : root(nullptr) { }

Tree::Tree(const std::string&amp; word)
    : root(new TreeNode(word)) { }

void Tree::add(const std::string&amp; word) {
    root = add_recursive(root, word);
}

void Tree::traverse() {
    traverse_recursive(root);
}

int Tree::get_num_nodes() const {
    return root-&gt;numChildren + 1; // +1 to count the root as a node
}

Tree::~Tree() {
    destroy_recursive(root);
}

TreeNode* Tree::add_recursive(TreeNode* n, const std::string&amp; word) {
    if (n == nullptr) {
        n = new TreeNode(word);
    } else if (word &lt; n-&gt;word) {
        n-&gt;left = add_recursive(n-&gt;left, word);
        n-&gt;numChildren++;
    } else if (word &gt; n-&gt;word) {
        n-&gt;right = add_recursive(n-&gt;right, word);
        n-&gt;numChildren++;
    } else {
        n-&gt;word = word;
    }

    return n;
}

void Tree::traverse_recursive(TreeNode* n) {
    if (n == nullptr) {
        return;
    }

    // Extended printing to visualize more info:
    std::cout &lt;&lt; "Node =&gt; " &lt;&lt; n-&gt;word &lt;&lt; ", numChildren: " &lt;&lt; n-&gt;numChildren;
    if (n-&gt;left != nullptr) {
        std::cout &lt;&lt; ", left: "  &lt;&lt; n-&gt;left-&gt;word;
    }
    if (n-&gt;right != nullptr) {
        std::cout &lt;&lt; ", right: " &lt;&lt; n-&gt;right-&gt;word;
    }
    std::cout &lt;&lt; "\n";

    traverse_recursive(n-&gt;left);
    traverse_recursive(n-&gt;right);
}

void Tree::destroy_recursive(TreeNode* n) {
    if (n == nullptr) {
        return;
    }
    destroy_recursive(n-&gt;left);
    destroy_recursive(n-&gt;right);
    delete n;
}

// main.cpp:

int main()
{
    Tree tree;

    tree.add("hello");
    tree.add("C++  ");
    tree.add("world");
    tree.add("foo  ");
    tree.add("bar  ");
    tree.add("baz  ");

    tree.traverse();

    std::cout &lt;&lt; "num nodes: " &lt;&lt; tree.get_num_nodes() &lt;&lt; std::end; // prints "num nodes: 6"
}