Binary tree implemented using references I implemented a binary tree using references because I couldn't see why people don't use references instead of pointers to implement data structures such as binary trees:

#include &lt;iostream&gt;

struct Node {
  Node(Node&amp; l, Node&amp; r, const char* v) : left_child(l), right_child(r), value(v) {}
  const char* value;
  Node&amp; left_child;
  Node&amp; right_child;
};

Node null_node(null_node, null_node, "END_OF_TREE");

bool is_leaf(Node&amp; node){
  return &amp;node.left_child == &amp;null_node &amp;&amp; &amp;node.right_child == &amp;null_node;
}

void post_order(Node&amp; node){
  if (is_leaf(node)){
    std::cout &lt;&lt; node.value;
  }
  else{
    if (&amp;node.left_child != &amp;null_node){
       post_order(node.left_child);
    }
    if (&amp;node.right_child != &amp;null_node){
       post_order(node.right_child);
    }
    std::cout &lt;&lt; node.value;
  }
}

int main(){
  Node n1(null_node, null_node, "1");
  Node n2(null_node, null_node, "2");
  Node n3(n1, n2, "3");
  Node n4(null_node, null_node, "4");
  Node n5(n3, n4, "5");
  post_order(n5);
}


I still can't see why references are inferior to pointers. What's wrong with using references for binary tree (other than that you can't insert or delete elements)? 

Also I'm completely new to C++ so any feedback on the code itself is appreciated as well. Thank you.
What's wrong with using references for binary tree (other than that you can't insert or delete elements)?


Well, it does work, as you've shown. But in order to use references instead of pointers, you had to make two awkward changes to the "natural" pointer-based code:

(1) You had to invent a null_node object, which is a global variable, and suffers all the problems of global variables (for example, it won't play well with dynamic libraries, a.k.a. shared objects, a.k.a. DLLs, because you might end up with a program containing two null_node variables — one from the main program and one from the DLL).

(2) You had to prefix all your accesses with an extra &amp; character.

Compare your way (slightly reformatted for style and const-correctness):

void post_order(const Node&amp; node) {
    if (&amp;node.left_child != &amp;null_node) {
        post_order(node.left_child);
    }
    if (&amp;node.right_child != &amp;null_node) {
        post_order(node.right_child);
    }
    std::cout &lt;&lt; node.value;
}


to the "natural" approach:

void post_order(const Node *node) {
    if (node-&gt;left_child) {
        post_order(node-&gt;left_child);
    }
    if (node-&gt;right_child) {
        post_order(node-&gt;right_child);
    }
    std::cout &lt;&lt; node-&gt;value;
}


Which one is easier to read (and incidentally to write)?

Notice that C++'s syntax for pointers dates back all the way to C, i.e., the mid-1970s. It's had a long time to polish and refine and streamline that syntax. You're trying to invent something "better", without the benefit of controlling the language definition. You shouldn't be surprised that the built-in, ~40-year-old syntax is really suitable for the exact job it was designed for. :)

By the way, if you want to deal with empty trees in the "natural" way, consider the following refactoring:

void post_order(const Node *node) {
    if (node != nullptr) {
        post_order(node-&gt;left_child);
        post_order(node-&gt;right_child);
        std::cout &lt;&lt; node-&gt;value;
    }
}


Straight-line code is best code!