c ++向量中的所有元素都指向同一个元素

时间:2013-06-01 16:46:13

标签: c++

我是c ++的初学者,到目前为止一直都很顺利。我对指针的想法很新(我来自python),我有这个奇怪的错误。

所以基本上,我创建了这个“SearchNode”类,并且在下面找到的是其中一个方法“getChildren”,它应该返回其他SearchNode实例的向量,表示Knight(棋盘)可以从中移动的可能单元格当前状态。 (BFS)

那就是说,当我完成推入向量时,所有元素突然只指向第一个元素。有人可以帮助我吗?

PS:这与c++ push_back doesn't work as it is supposed的问题类似......但与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();
}
};

1 个答案:

答案 0 :(得分:6)

很多错误和错误,我强烈建议您在编译器中调高警告级别,以便获得更多信息。使用GCC / G ++ / Clang,尝试“-Wall”或“-Wextra”,正如moshbear指出的那样。

您的节点永远不会被分配“父”值,您正在创建一个名为“父”的“影子”局部变量并指定它。为了避免像这样的常见错误,请使用成员变量名称的前缀或后缀将它们与本地名称分开,例如: “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&gt; 2012,GCC&gt; = 4.8,Clang&gt; = 4.1)将允许您用

替换前两个构造函数
// 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_)
        {}
};