首页 > 解决方案 > 使用默认复制构造函数会破坏 C++ 中的树

问题描述

例如:

#include <iostream>
#include <vector>
#include <string>

using namespace std;

struct TreeNode {
    vector<TreeNode> children;
    string name;
};

int main() {
    TreeNode leafNode;
    leafNode.name="c";
    TreeNode middleNode;
    middleNode.name="b";
    middleNode.children.push_back(leafNode);
    TreeNode rootNode;
    rootNode.name="a";
    rootNode.children.push_back(middleNode);
    rootNode=rootNode.children[0];
    cout <<rootNode.name <<endl;
}

输出c,在 CLANG 和 GCC 中。当然,我希望它输出b. 这里发生了什么?

标签: c++

解决方案


正如其他人在评论中指出的那样,您真的应该尝试设置调试器并首先调试您的代码。这就是你在编程中学到很多东西的方式。

但是,如果您不习惯调试,您可能很难找到问题所在,因为有问题的代码是编译器生成的。

您是对的,复制构造函数或多或少会损坏您的数据。但这不是编译器的错。默认复制构造函数通过引用获取其参数,并且您将 的成员的引用传递rootNode给 的复制构造函数rootNode。所以实际上你是用它自己的一部分覆盖对象。

在分配或复制过程中或多或少发生了什么:

TreeNode(const TreeNode& other) {
  children = other.children;
  name = other.name;
}

因此,如果您传递rootNode.children[0]给此操作,它将有效地简化为:

rootNode.children = rootNode.children[0].children; // copies the children of 'b' to 'a'
rootNode.name     = rootNode.children[0].name;     // children[0] now refers to the first 
                                                   // of 'b's children, so name will be 'c' !!

一种可能的解决方法是首先使用以下方法创建真实副本:

rootNode = TreeNode{ rootNode.children[0] };

行为可能因编译器而异。在 VS2019 中,我在尝试您的示例时得到一个空输出。


推荐阅读