Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Compiler allows circular definition?

Tags:

I ran into the following oddity when making a mistake writing some code for trees. I've stripped down this example a lot so it is only a Linear Tree.

Basically, in the main() function, I wanted to attach a Node to my tree, but instead of attaching it to "tree.root", I attached it to just "root". However, to my surprise, not only did it all compile just fine, but I was able to call methods on the nodes. It only errored when I tried to access the "value" member variable.

I guess my main question is, why didn't the compiler catch this bug?

std::shared_ptr<Node> root = tree.AddLeaf(12, root); 

Since "root" on the RHS is a flat-out undeclared variable. Also, out of curiosity, if the compiler lets them through, do circular definitions have an actual use case? Here's the rest of the code:

#include <iostream> #include <memory>  struct Node {     int value;     std::shared_ptr<Node> child;      Node(int value)     : value {value}, child {nullptr} {}      int SubtreeDepth()     {         int current_depth = 1;         if(child != nullptr) return current_depth + child->SubtreeDepth();         return current_depth;     } };  struct Tree {     std::shared_ptr<Node> root;      std::shared_ptr<Node> AddLeaf(int value, std::shared_ptr<Node>& ptr)     {         if(ptr == nullptr)         {             ptr = std::move(std::make_shared<Node>(value));             return ptr;         }         else         {             std::shared_ptr<Node> newLeaf = std::make_shared<Node>(value);             ptr->child = std::move(newLeaf);             return ptr->child;         }     } };   int main(int argc, char * argv[]) {      Tree tree;     std::shared_ptr<Node> root = tree.AddLeaf(12, root);     std::shared_ptr<Node> child = tree.AddLeaf(16, root);      std::cout << "root->SubtreeDepth() = " << root->SubtreeDepth() << std::endl;      std::cout << "child->SubtreeDepth() = " << child->SubtreeDepth() << std::endl;       return 0; } 

Output:

root->SubtreeDepth() = 2 child->SubtreeDepth() = 1 
like image 478
Paradox Avatar asked Jan 07 '19 10:01

Paradox


People also ask

What is circular in C?

A circular reference in computer programming is a situation in which two values reference each other. This type of reference can be extremely problematic if two functions or values depend on one another for definition.

What is called as circular definition in C++?

A circular definition is a description that uses the term(s) being defined as part of the description or assumes that the term(s) being described are already known.


Video Answer


1 Answers

That's an unfortunate side-effect of definitions in C++, that declaration and definition is done as separate steps. Because the variables are declared first, they can be used in their own initialization:

std::shared_ptr<Node> root = tree.AddLeaf(12, root); ^^^^^^^^^^^^^^^^^^^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^^ Declaration of the variable  Initialization clause of variable 

Once the variable is declared, it can be used in the initialization for the full definition of itself.

It will lead to undefined behavior in AddLeaf if the data of the second argument is used, as the variable is not initialized.

like image 157
Some programmer dude Avatar answered Sep 19 '22 11:09

Some programmer dude