0

決定木を表すモジュールがあります。Choice (外部クラス Event から継承) と Option の 2 つのクラスがあります。Choice は決定木のノードを表し、Option は分岐を表します。Choice には少なくとも 1 つの Option が必要です。Option は Choice を持つことも、持たないこともできます。Option に Choice がない場合、それは最終的な Option です。

たとえば、デシジョン ツリーが次のようになっているとします。

A----B  
 |  
 ----C----D  
     |  
     -----E  

A は、2つ
のオプション (B と C) を持つ選択肢になります。
B は、選択肢のないオプション (つまり、ターミナル オプション) になります。
C は、選択肢を持つオプションになります。C's Choice には、オプション D と E が含まれます。

意思決定ツリーを必要なだけ深くできるようにコードを作成しました。これが、オプションに選択肢があり、選択肢にオプションがある理由です。

関数 function find_terminal_options_in(EventPtr ch) があり、すべての端末オプションを見つけてその名前を取得する再帰呼び出しがあります。この例では、find_terminal_options_in(ptr_to_A) は {"B","D","E"} を返す必要があります。代わりに、オプション C の選択を処理している 2 番目の呼び出しの最後に失敗します。次のエラーが発生して失敗します。

デバッグ アサーションに失敗しました!
式: _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;
}
4

2 に答える 2

0

問題は次のとおりです。

virtual ~Event() {}

クラスイベントで。関数呼び出しスタックから戻るとすぐに、インスタンス「ch」が削除されます。

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

ただし、main() で構築されているにもかかわらず、Choice の Deconstructor は呼び出されません。

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

"virtual ~Event()" で試してみると、問題は解消されます。:-)

于 2014-07-17T17:26:30.113 に答える
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)));

適切な修正 - Option の Choice ではなく、Choice への共有ポインタを格納する。

于 2013-10-30T21:59:57.007 に答える