在为树写一些代码时犯了一个错误,我遇到了以下奇怪的问题.我已经删除了很多这个例子,所以它只是一个线性树.
基本上,在main()函数中,我想将一个Node附加到我的树上,但是我没有将它附加到"tree.root",而是将它附加到"root".但是,令我惊讶的是,它不仅编译得很好,而且我能够在节点上调用方法.它只在我尝试访问"value"成员变量时出错.
我想我的主要问题是,为什么编译器没有抓到这个bug?
std::shared_ptr<Node> root = tree.AddLeaf(12, root);
Run Code Online (Sandbox Code Playgroud)
由于RHS上的"根"是一个平坦的未声明变量.另外,出于好奇,如果编译器让它们通过,那么循环定义是否具有实际用例?这是代码的其余部分:
#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;
}
Run Code Online (Sandbox Code Playgroud)
输出:
root->SubtreeDepth() = 2
child->SubtreeDepth() = 1
Run Code Online (Sandbox Code Playgroud)
Som*_*ude 23
这是C++中定义的一个不幸的副作用,声明和定义是作为单独的步骤完成的.因为变量是先声明的,所以可以在自己的初始化中使用它们:
std::shared_ptr<Node> root = tree.AddLeaf(12, root);
^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
Declaration of the variable Initialization clause of variable
Run Code Online (Sandbox Code Playgroud)
声明变量后,可以在初始化中使用它来完成自身的定义.
这将导致未定义的行为中AddLeaf,如果使用第二个参数的数据,作为变量未初始化.
eer*_*ika 13
由于RHS上的"根"是一个平坦的未声明变量.
这不是未宣布的.它是由同一个声明宣布的.然而,root 被在其中点未初始化AddLeaf(root)被调用,所以当使用对象的值(相对于空等)的函数中,该行为是未定义.
是的,允许在自己的声明中使用变量,但使用其值不是.几乎所有你可以用它来做的是获取地址或创建一个引用,或只处理子表达式类型的表达式,如sizeof和alignof.
是的,有用例虽然可能很少见.例如,您可能希望表示一个图形,并且您可能有一个节点构造函数,它将指向链接节点的指针作为参数,您可能希望能够表示与其自身链接的节点.因此你可以写Node n(&n).我不会争论这对于图形API是否是一个好的设计.