我有一個表示決策樹的模塊。我有兩個類:Choice(從外部類事件繼承)和Option。選擇表示決策樹的節點,選項表示分支。選擇必須至少有一個選項。一個選項可以有一個選擇或不選擇。如果一個期權沒有選擇權,它是一個終端期權。遞歸函數調用時出現block_type_is_valid錯誤
如果舉例來說,如果決策樹是這樣的:
A----B
|
----C----D
|
-----E
然後:
A將是一個選擇有兩個選項(B和C)。
B將是沒有選擇權的選項(即終端選項)。
C將是一個有選擇的選項。 C的選擇將包含選項D和E.
我已經編寫了我的代碼,以使決策樹可以根據需要儘可能深,這就是爲什麼選項有選項並且選項有選項。
我有一個函數函數find_terminal_options_in(EventPtr通道)與遞歸調用,找到所有終端選項並獲取他們的名字。在這個例子中,find_terminal_options_in(ptr_to_A)應該返回{「B」,「D」,「E」}。相反,在第二次調用結束時,它在處理選項C的選擇時失敗。它失敗,給出以下錯誤:
Debug Assertion Failed!
Expression: _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;
}