实现家谱时出现 C++ 核心转储错误

C++ core dump error while implementing family tree

我正在尝试实现家谱。我有 类 PersonTree 定义如下:

文件FamilyTree.hpp:

using namespace std;
#include <string>

namespace family{

    class Person{
        public:
        string name;
        Person* mother;
        Person* father;

        Person(string name);

    };

    class Tree{
        public:
        Person* root;

        Tree(string name);

        Tree& addFather(string name1, string name2);
        Tree addMother(string name1, string name2);
        void display();
        string relation(string name);
        string find(string name);
        void remove(string name);
    };

};

文件FamilyTree.cpp:

#include "FamilyTree.hpp"
#include <string>
#include <iostream>
using namespace family;   

// FUNCTIONS

Person& findPerson(Person& root, string child_name){
    if (root.name.compare(child_name) != 0)
    {
        cout<<root.name<<":1"<<endl;
        findPerson(*root.father, child_name);
    }
    else if(root.name.compare(child_name) == 0){
        cout<<root.name<<":2"<<endl;
        return root;  
    }else{
        cout<<"not found!!!"<<endl;
        Person p("no found");
        return p;
    }
}

// PERSON
family::Person::Person(string person_name){
    name = person_name;
    father = nullptr;
    mother = nullptr;
};

// TREE
family::Tree::Tree(string name){
    root = new Person(name);
};

family::Tree& Tree::addFather(string child, string father){
    Person& child_found = findPerson(*root, child);

    //cout<<"child_found.name:"<<child_found.name<<endl;
    child_found.father = new Person(father);
    return *this;
    };

family::Tree family::Tree::addMother(string name1, string name2){return Tree("");};
void family::Tree::display(){};
string family::Tree::relation(string name){return "";};
string family::Tree::find(string name){return "";};
void family::Tree::remove(string name){};

int main(){
    Tree t("X");

    t.addFather("X", "Y");
    t.addFather("Y","Z");
    return 0;
}

我从 addFather() 函数开始: addFather("child", "new father") 为现有 child 添加新父亲。 我使用 findPerson() 函数递归实现它,其中 returns Person object 用于 child 和 addFather() 函数创建新的 Person并将其初始化以找到 child.

添加2个父亲后,出现Illegal instruction (core dumped)错误,请问是什么问题?

如果您打开警告,您会发现您并不总是 return来自 findPerson。在这个函数中

Person& findPerson(Person& root, string child_name){
    if (root.name.compare(child_name) != 0)
    {
        cout<<root.name<<":1"<<endl;
        findPerson(*root.father, child_name);      // (1)
    }
    else if(root.name.compare(child_name) == 0){
        cout<<root.name<<":2"<<endl;
        return root;  
    }else{
        cout<<"not found!!!"<<endl;
        Person p("no found");
        return p;                      // (2)
    }
}

第一个 if 分支中的代码,标记为 (1),需要 return 递归找到的人,像这样

return findPerson(*root.father, child_name);

这应该可以解决段错误。

但是,在该函数的最后一个分支中存在更深层次的问题,您在此处 return 引用局部变量 p,标记为 (2)。如果你这样做,你就是 return 悬空引用,因为当函数 returns.

p 将超出范围

你要想想这个函数在没有找到Person的情况下应该做什么。

  • 你可能会 return 一个 Person*,所以 nullptr 意味着找不到人。

  • 你可以 return 一个 std::optional<Person>

问题是您不能 return 对本地对象的引用。这将导致未定义的行为。

当你添加一个新成员时,findPerson() 将不会尝试return 找到它这样的本地对象p。这是注定要失败的。

这个设计不是最优的。可能的解决方案:

  • 声明一个静态对象 p,当没有找到时 returned。与局部变量不同,static 仍然有效,然后引用 returned 将保持有效。但是,您必须确保绝不会以可能更改静态对象名称的方式使用此 returned 引用。
  • 更改 findPerson() 的接口,使其 return 指针。它要么 return 是指向某个人的有效指针,要么 return 是 nullptr 如果找不到任何东西。这是一个常见的习惯用法(在现实世界的开发中,你会 return 一个迭代器,但如果你是从 C++ 开始,这暂时就太复杂了)。
  • 如果未找到任何内容,则抛出异常并重写调用代码以捕获异常。我不建议在这里使用这种方法:在真正特殊的情况下最好保留例外。

请注意,如果还有其他错误,我没有查看您的代码。我只是在第一次尝试寻找当树为空时不存在的东西时停下来。

它适用于父亲搜索,但我需要它来遍历整个树。 当我加了mothers root的时候,它又核心转储了。

Person& findPerson(Person& root, string child_name){
    if (root.name.compare(child_name) != 0)
    {
        //cout<<root.name<<":1"<<endl;
        return findPerson(*root.father, child_name); 
        return findPerson(*root.mother, child_name);     // (1)
    }
    else if(root.name.compare(child_name) == 0){
        //cout<<root.name<<":2"<<endl;
        return root;  
    }else{
        throw exception();                     
    }
}