C++ 块类型是递归函数调用的有效错误

C++ 块类型是递归函数调用的有效错误,c++,recursion,shared-ptr,C++,Recursion,Shared Ptr,我有一个表示决策树的模块。我有两个类:Choice(从外部类事件继承)和Option。选项表示决策树的节点,选项表示分支。一个选项必须至少有一个选项。选项可以选择,也可以不选择。如果一个选项没有选择权,它就是一个终端选项 例如,如果决策树如下所示: A----B | ----C----D | -----E 然后: A将是一个有两个选项(B和C)的选择。 B将是一个没有选择的选项(即终端选项)。 C将是一个有选择的选项。C的选择将包含选项D和E 我编写

我有一个表示决策树的模块。我有两个类:Choice(从外部类事件继承)和Option。选项表示决策树的节点,选项表示分支。一个选项必须至少有一个选项。选项可以选择,也可以不选择。如果一个选项没有选择权,它就是一个终端选项

例如,如果决策树如下所示:

A----B  
 |  
 ----C----D  
     |  
     -----E  
然后:
A将是一个有两个选项(B和C)的选择。
B将是一个没有选择的选项(即终端选项)。
C将是一个有选择的选项。C的选择将包含选项D和E

我编写的代码允许决策树尽可能深入,这就是为什么选项有选项,选项有选项的原因

我有一个函数find_terminal_options_in(EventPtr ch),它带有一个递归调用,用于查找所有终端选项并获取它们的名称。在本例中,find_terminal_options_In(ptr_to_A)应返回{“B”、“D”、“E”}。相反,它在处理选项C的选择时,在第二次调用结束时失败。由于出现以下错误,因此失败:

调试断言失败
表达式:\块\类型\有效(pHead->nBlockUse)

在共享的_ptr析构函数中调用

发生此错误是因为我的设计中存在缺陷还是因为我使用共享ptr的方式存在缺陷?关于如何消除这个运行时错误,有什么建议吗

请参阅我的(简化)代码,它再现了问题:

class Event {
public:
    Event(std::string name):name_(name) {};
    std::string name() {return name_;};
    virtual bool is_terminal() = 0;
protected:
    std::string name_;
};

class Option;

class Choice: public Event {
public:
    Choice(): Event("") {};
    Choice(std::string name, std::list<Option> options): Event(name) {options_ = options;};
    std::list<Option> options() {return options_;};
    std::string name() {return name_;};
    bool is_terminal() {return false;};
private:
    std::list<Option> options_;
};

class Option
{
public:
    Option(std::string name, Choice choice):name_(name),choice_(choice) {};
    Option(std::string name):name_(name) {};
    Choice choice() {return choice_;};
    std::string choice_name() {return choice_.name();};
    std::string option_name() {return name_;};
private:
    Choice choice_;
    std::string name_;
};

typedef std::shared_ptr<Event> EventPtr;
typedef std::shared_ptr<Event> ChoicePtr;

std::list<std::string> find_terminal_options_in(EventPtr ch);

int main() {
    std::list<Option> temp_opts1;
    temp_opts1.push_back(Option("D"));
    temp_opts1.push_back(Option("E"));
    Choice option_Cs_choice("option_Cs_choice",temp_opts1);

    std::list<Option> temp_opts2;
    temp_opts2.push_back(Option("C",option_Cs_choice));
    temp_opts2.push_back(Option("B"));
    EventPtr ptr_to_A = EventPtr(new Choice("A",temp_opts2));

    std::list<std::string> terminal_options = find_terminal_options_in(ptr_to_A);
}

std::list<std::string> find_terminal_options_in(EventPtr ch)
{
    std::list<std::string> returned_list;

    std::shared_ptr<Choice> choice = std::dynamic_pointer_cast<Choice>(ch);
    std::list<Option> choice_options = choice->options();

    for(std::list<Option>::iterator options_it = choice_options.begin();options_it != choice_options.end(); options_it++)
    {
        if(options_it->choice_name() != "") //it has a choice
        {
            Choice option_choice = options_it->choice();
            find_terminal_options_in(EventPtr(&option_choice));
        }
        else //it doesn't have a choice, and is therefore a terminal option
            returned_list.push_back(options_it->option_name());
    }

    return returned_list;
}
类事件{
公众:
事件(std::string name):名称{(name){};
std::string name(){返回名称};
虚拟布尔是_terminal()=0;
受保护的:
std::字符串名称;
};
类别选择权;
课程选择:公共活动{
公众:
Choice():事件(“”{};
选项(std::string name,std::list options):事件(name){options_u=options;};
std::list options(){返回选项};
std::string name(){返回名称};
bool是_terminal(){return false;};
私人:
std::列出选项;
};
类选项
{
公众:
Option(std::string name,Choice-Choice):name_u(name),Choice_u(Choice){};
选项(std::string name):名称{(name){};
Choice Choice(){返回Choice_;};
std::string choice_name(){return choice_u.name();};
std::string选项_name(){return name_;};
私人:
选择,;
std::字符串名称;
};
typedef std::shared_ptr EventPtr;
typedef std::共享_ptr ChoicePtr;
std::在(EventPtr ch)中列出查找终端选项;
int main(){
std::列出临时选项1;
临时选项1.向后推(选项(“D”);
临时选项1.向后推(选项(“E”);
选项选择(“选项选择”,临时选项1);
std::列出临时选项2;
临时选项2.向后推(选项(“C”,选项“C”);
临时选项2.向后推(选项(“B”);
EventPtr ptr_to_A=EventPtr(新选项(“A”,临时选项2));
std::list terminal_options=在(ptr_to_A)中查找_terminal_options_;
}
std::列出查找终端选项(EventPtr ch)
{
std::列表返回\u列表;
std::shared_ptr choice=std::dynamic_pointer_cast(ch);
std::list choice_options=choice->options();
对于(std::list::iterator options_it=choice_options.begin();options_it!=choice_options.end();options_it++)
{
if(options\u it->choice\u name()
{
Choice option\u Choice=options\u it->Choice();
在(EventPtr(&option_choice))中查找终端选项;
}
else//它没有选择余地,因此是一个终端选项
返回的列表。向后推(选项\u it->选项\u name());
}
返回列表;
}

您的代码有两个问题:

  • 为了使递归正常工作,您需要将签名从

    std::在(EventPtr ch)中列出查找终端选项

  • 他迷路了

  • 一致

    find_terminal_options_in(EventPtr(&option_choice));
    
  • 您正在从非动态分配的对象创建共享指针—这是无法完成的,这就是您得到错误的原因。只能从使用“新建”创建的对象实例化共享指针。快速解决方法是

            find_terminal_options_in(EventPtr(new Choice(option_choice)));
    

    正确修复-存储指向选项的共享指针,而不是选项中的选项。

    问题是:您错过了

    virtual ~Event() {}
    
    课堂活动。 一旦从函数调用堆栈返回,实例“ch”就会被删除

    std::list<std::string>  find_terminal_options_in(EventPtr ch)  { ... }
    
    使用“virtual~Event()”进行尝试,问题将消失。:-)

    virtual ~Event() {}
    
    std::list<std::string>  find_terminal_options_in(EventPtr ch)  { ... }
    
    EventPtr ptr_to_A = EventPtr(new Choice("A",temp_opts2));