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

All elements in a c++ vector point to the same element

本文关键字:元素 同一个 vector c++      更新时间:2023-10-16

我是一个完全的c++初学者,直到现在一切都很顺利。我对指针的概念很陌生(我来自python),我有这个奇怪的错误。

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

也就是说,当我完成压入向量时,所有元素突然只指向第一个元素。有人能帮我一下吗?

PS:这是一个类似于c++的问题push_back没有't工作,因为它应该…但不像Angela(她在写自己的编译器),我完全是c++的初学者。非常感谢您的帮助。

去掉了int*,用数组表示状态。我现在可以成功地搜索图(因此状态是ok的)并找到最短路径,但我似乎无法重建路径。

为了测试,我从{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();
}
};

有很多错误和错误,我强烈建议您在编译器中打开警告级别,以便您可以获得更多信息。在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指出的那样,这种副作用不是你可以指望的,在这种情况下只是排序的产物)。

在节点结构中使用简单的整型数组可能比使用指针更容易。

如果你的编译器是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)将允许您用

替换前两个构造函数。
// 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++的编译器,你可以把这一切归结为:

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_)
        {}
};