C ++编译器允许循环定义吗? [英] C++ Compiler allows circular definition?
问题描述
在为树写一些代码时犯了一个错误。我已经精简了这个示例,所以它只是一个线性树。
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.
基本上,在main()函数中,我想将Node附加到我的树上,但没有将其附加到 tree.root,而是将其仅附加到 root。但是,令我惊讶的是,不仅可以很好地进行编译,而且我能够在节点上调用方法。
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);
由于RHS上的根是一个完全未声明的变量。另外,出于好奇,如果编译器允许它们通过,则循环定义是否具有实际用例?以下是其余的代码:
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;
}
输出:
root->SubtreeDepth() = 2
child->SubtreeDepth() = 1
推荐答案
这是C ++中定义的不幸副作用,声明和定义是单独进行的。因为首先声明了变量 ,所以它们可以在自己的初始化中使用:
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.
它将导致 AddLeaf 中的rel = noreferrer> 未定义行为 初始化。
It will lead to undefined behavior in AddLeaf
if the data of the second argument is used, as the variable is not initialized.
这篇关于C ++编译器允许循环定义吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!