2013-10-30 54 views
0

我有一個表示決策樹的模塊。我有兩個類: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; 
} 

回答

0

有2個問題,你的代碼:

  1. 遞歸正常工作,您需要從改變簽名

    std :: list find_terminal_options_in(EventPtr ch);

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

要創建非動態分配的對象共享指針 - 不能做的,這是你所得到的埃羅的原因。您只能從使用new創建的對象實例化共享指針。快速修復是

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

適當的修復 - 共享存儲指向選擇,而不是選擇的選擇。

0

的問題是:你在類的事件錯過了

virtual ~Event() {} 

。 一旦從函數調用堆棧返回,實例「ch」將被刪除。

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

但它並沒有調用Choice's Deconstructor,雖然它是在main()中構造的。

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

用「virtual〜Event()」試一試,問題就會消失。 :-)

相關問題