递归函数调用时出现block_type_is_valid错误

时间:2013-10-30 21:34:34

标签: c++ recursion shared-ptr

我有一个代表决策树的模块。我有两个类:Choice(继承自外部类Event)和Option。 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的选择时。它失败了,提出以下错误:

  

Debug Assertion失败!
  表达式:_BLOCK_TYPE_IS_VALID(pHead-> nBlockUse)

在shared_ptr析构函数中调用。

由于我的设计存在缺陷或我使用shared_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;
}

2 个答案:

答案 0 :(得分:0)

您的代码有两个问题:

  1. 要使递归正常工作,您需要从

    更改签名

    std :: list find_terminal_options_in(EventPtr ch);

  2. void find_terminal_options_in(EventPtr ch,std::list<std::string> &output);
    

    否则,数据在

    中获得
    find_terminal_options_in(EventPtr(&option_choice));
    

    丢失了。

    1. 排队

      find_terminal_options_in(EventPtr(&option_choice));
      
    2. 您正在从非动态分配的对象创建共享指针 - 这是无法完成的,这就是您获得错误的原因。您只能从使用new创建的对象实例化共享指针。快速修复

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

      正确修复 - 将选择指针存储到Choice而非选项中的选择。

答案 1 :(得分:0)

问题是:你错过了

virtual ~Event() {}
课程中的

。 一旦从函数调用堆栈返回,实例&#34; ch&#34;将被删除。

std::list<std::string>  find_terminal_options_in(EventPtr ch)  { ... }

但是它并没有调用Choice的解构器,尽管它是用main()构造的。

EventPtr ptr_to_A = EventPtr(new Choice("A",temp_opts2));

尝试使用&#34;虚拟〜事件()&#34;问题就会消失。 : - )