C ++编译器允许循环定义吗? [英] C++ Compiler allows circular definition?

查看:79
本文介绍了C ++编译器允许循环定义吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在为树写一些代码时犯了一个错误。我已经精简了这个示例,所以它只是一个线性树。

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆