【问题标题】:C++ core dump error while implementing family tree实现家谱时出现 C++ 核心转储错误
【发布时间】:2020-07-17 12:32:40
【问题描述】:

我正在尝试实现家谱。我的类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") 为现有孩子添加新父亲。 我使用findPerson() 函数递归地实现了它,该函数返回子对象的Person 对象和addFather() func 创建新的Person 并将其初始化为找到的子对象。

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

【问题讨论】:

    标签: c++ compiler-errors core coredump


    【解决方案1】:

    它适用于父亲搜索,但我需要它来遍历整个树。 当我添加母亲根时,它再次核心转储。

    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();                     
        }
    }
    

    【讨论】:

    • 这个有什么解决办法吗?
    【解决方案2】:

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

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

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

    • 声明一个静态对象p,当什么都没找到时返回。与本地人不同,静态保持活动状态,然后返回的引用将保持有效。但是,您必须确保返回的引用永远不会以可能更改静态对象名称的方式使用。
    • 更改findPerson() 的接口,使其返回指针。它要么返回指向人员的有效指针,要么返回nullptr,如果没有找到。这是一个常见的习惯用法(在现实世界的开发中,您将返回一个迭代器,但如果您从 C++ 开始,这暂时太复杂了)。
    • 如果未找到任何内容,则抛出异常并重写调用代码以捕获异常。我不建议在这里使用这种方法:异常最好保留在非常特殊的情况下。

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

    【讨论】:

      【解决方案3】:

      如果您打开警告,您会发现您并非总是从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-branch中的代码,标记为(1),需要返回递归找到的Person,像这样

      return findPerson(*root.father, child_name);
      

      这应该处理段错误。

      但是,在此函数的最后一个分支中存在一个更深层次的问题,您将返回对局部变量 p 的引用,标记为 (2)。如果您这样做,您将返回一个悬空引用,因为当函数返回时,p 将超出范围。

      你需要考虑如果没有找到 Person,这个函数应该做什么。

      • 您可能会返回一个Person*,所以nullptr 表示找不到Person。

      • 您可以返回std::optional&lt;Person&gt;

      【讨论】:

      • 这是一个非常全面的答案。我立即发现返回的是对本地人的引用,但在我的回答中,我没有注意到丢失的返回。干得好+1
      • 现在完美运行,但我现在的问题是:为什么我应该返回函数? IF 状态不应返回任何内容。因为我的 ELSE IF 状态对此负责。
      • C++ 的一个规则是,如果一个函数说它会返回一些东西,它必须返回一些东西。除此之外,看起来函数的逻辑需要递归返回。就编译器而言,这不是必需的,但返回 something 是。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-11
      • 2015-07-27
      • 2021-03-17
      相关资源
      最近更新 更多