-3

私は C++ の完全な初心者で、今まですべて順調に進んでいます。私はポインターのアイデアに慣れていません(私はpythonから来ました)、この奇妙なエラーがあります。

基本的に、私はこの「SearchNode」クラスを作成しました。以下は、ナイト (チェス盤) が現在の状態から移動できる可能性のあるセルを表す、他の SearchNode インスタンスのベクトルを返す必要があるメソッド「getChildren」の 1 つです。(BFS)

そうは言っても、ベクターへのプッシュを終了すると、すべての要素が突然最初の要素のみを指します。誰かがここで私を助けてくれますか?

PS: c++ push_back が想定どおりに機能しないのと同様の問題ですが、Angela (自分でコンパイラを作成していた) とは異なり、私は c++ の初心者です。どうぞよろしくお願いいたします。

アップデート

int* を取り除き、状態に配列を使用しました。グラフを正常に検索し (したがって、状態は問題ありません)、最短経路を見つけることができましたが、経路を再構築することはできなかったようです。

テストするために、{0,0} から始めて {4,4} を見つけることができましたが、getPath メソッドによるパスは {4,4}、{3,6}、{3,6}、{3 でした。 ,6} ... ({3,6} の無限ループ)。親ポインターまたは getPath 関数に何か問題がありますか? 事前にご支援いただきありがとうございます。

//Search class
class SearchNode
{
public:
//Variables
SearchNode *m_parent;
array<int,2> m_state; //I don't understand typedef's yet, will use them when I'm clearer with them :)

//Normal Constructor
SearchNode(array<int,2>& state_, SearchNode *parent_=nullptr) :
m_state(state_),
m_parent(parent_)
{}


//Method to get Next reachable states. Returns instances of SearchNode.
vector<SearchNode> getChildren()
{
    int legalMoves[8][2] = {{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}};

    vector<SearchNode> children;
    children.reserve(8);
    for(int i=0; i<8; i++)
    {
        int x = (m_state[0] + legalMoves[i][0]);
        int y = (m_state[1] + legalMoves[i][1]);
        if( (x>-1) and (x<9) and (y<9) and (y>-1)) // Within the bounds of the board
        {
            array<int,2> childState = {x,y};
            SearchNode childNode = SearchNode(childState,this);
            children.push_back(childNode);
        }
    }
    return children;
}

void getPath()
{
    cout<<"\nPath: ";
    cout<<  this->print();
    SearchNode current = *this;
    unsigned int counter = 1;
    while((current.m_parent!=nullptr) and counter< 10)
    {
        counter++;
        cout<< (current.m_parent)->print();
        current = *(current.m_parent);
    }
    cout << (current.m_parent)->print();
}

string print()
{
    stringstream out;
    out << "{" << this->m_state[0] << "," << this->m_state[1] << "} ";
    return out.str();
}
};
4

1 に答える 1

6

多くの間違いやエラーがあります。より多くの情報を取得できるように、コンパイラの警告レベルを上げることを強くお勧めします。GCC/G++/Clang では、moshbear が指摘しているように、「-Wall」または「-Wextra」を試してください。

ノードに「親」値が割り当てられることはありません。「親」と呼ばれる「シャドウ」ローカル変数を作成して割り当てます。このような一般的なエラーを回避するには、メンバー変数名に接頭辞または接尾辞を使用して、"m_parent" や "_parent" などのローカル名と区別します。

コンストラクターでデフォルト値を割り当てず、明示的に値を初期化しないままにします。

SearchNode()
{
    //do nothing
}

次に、このガベージデータをポインターベースのコンストラクターに導入します。おそらく必要なのは

SearchNode() : parent(NULL), state(NULL) {}

あなたのコピーコンストラクターは災害です。ポインターとローカル変数を読んで理解する必要があります。

//Start Node constructor. Still looking for an equivalent for null.
SearchNode(int *state)
{
    int genericStartState[2] = {-1,-1};
    SearchNode blankParent = SearchNode();
    SearchNode genericStart = SearchNode(genericStartState,&blankParent);
    this->parent = &genericStart;
    this->state=state;
}

まず、ここでの「blankParent」は、現在のコピー コンストラクターによるランダム データを含むローカル変数です。次に、ルーチンの最後で「}」を押すと存在を停止しようとしている、プライベートなローカル変数のアドレスを取得しています。

「genericStartState」も対象外です。

それを除けば、この特定のコンストラクターは必要ないと思います。

しかし、根本的に、あなたの件名のバグは、割り当てループで同じことを行うためです.一時的なローカル配列を使用して新しい値を格納し、それへのポインターをコンストラクターに渡します。アドレスを取得しているため、ループごとに同じになります。

    int childState[2] = { x, y };
    SearchNode childNode = SearchNode(childState,this);

これが、すべてのノードが同じ状態になっている理由です。それらはすべて同じメモリ位置を指しているためです (編集: DyP が指摘したように、その副作用は当てにできるものではなく、この順序付けの人工物にすぎません)場合)。

ノード構造では、ポインターよりも単純な int 配列を使用する方が簡単な場合があります。

コンパイラが VisualStudio 2012 または G++ 4.8 または Clang 4.2 の場合、コンストラクター側は次のようになります。

class SearchNode
{
public:
    typedef std::array<int, 2> State;

private:
    // I use the 'm_' convention for members, 'g_' for globals, 's_' for statics.
    SearchNode* m_parent;
    State       m_state;

public:
    //////////
    // Default ctor.
    SearchNode()
        : m_parent(nullptr) // C++11 constant meaning pointer with value 0
        , m_state({-1, -1}) // preferred but requires recent C++11 features
    {
        //m_state[0] = m_state[1] = -1; // had to do this instead for gcc 4.7.3
    }

    //////////
    // Normal ctor
    // I use the '_'-postfix convention for parameter names.
    SearchNode(SearchNode* parent_, const State& state_)
        : m_parent(parent_)
        , m_state(state_)
    {
    }

    //////////
    // Copy constructor.
    // We could do this, but it's the default behavior anyway.
    /*
    SearchNode(const SearchNode& rhs)
        : m_parent(rhs.m_parent)
        , m_state(rhs.m_state)
    {
    }
    */

    // Current C++11 compilers let us be explicit and do this:
    //SearchNode(const SearchNode& rhs) = default;

    // But it's the default behavior so we don't have to do this one at all.
};

最新の C++11 言語の変更 (MSVC > 2012、GCC >= 4.8、Clang >= 4.1) では、最初の 2 つのコンストラクターを次のように置き換えることができます。

// Kill two birds with one stone and have default parameters on our normal ctor,
// replacing both the default and normal ctor with one function.
SearchNode(SearchNode* parent_ = nullptr, const State& state_ = { -1, -1 }))
    : m_parent(parent_)
    , m_state(state_)
{       
}

C++1y と完全に互換性のあるコンパイラを使用している場合は、次のようにまとめることができます。

class SearchNode
{
public:
    typedef std::array<int, 2> State;

private:
    // I use the 'm_' convention for members, 'g_' for globals, 's_' for statics.
    SearchNode* m_parent = nullptr; // c++1y keyword to replace 'NULL'
    State       m_state = { -1, -1 };

public:
    SearchNode() = default;
            SearchNode(const State& rhs_) = default; // not strictly required.
    SearchNode(SearchNode* parent_, const State& state_)
        : m_parent(parent_), m_state(state_)
        {}
};
于 2013-06-02T04:50:44.360 に答える