C++ 循环遍历C+中类中包含的向量+;不复制影响值?

C++ 循环遍历C+中类中包含的向量+;不复制影响值?,c++,pointers,vector,stdvector,C++,Pointers,Vector,Stdvector,我正在尝试编写一个算法来检查一个图是否是连通的(构建一个棋盘游戏,其中地图包含为一个图,其中区域是顶点,边界是边) 每个区域都包含一个作为其邻居的区域向量(向量邻居) 我在main()函数中构建映射并检查其是否连接: int main() { Map map; Region r1("R1"); Region r2("R2"); Region r3("R3"); r1.addNeighbor(r2); r2.addNeighbor(r1);

我正在尝试编写一个算法来检查一个图是否是连通的(构建一个棋盘游戏,其中地图包含为一个图,其中区域是顶点,边界是边)

每个区域都包含一个作为其邻居的区域向量(向量邻居)

我在main()函数中构建映射并检查其是否连接:

int main()
{
    Map map;
    Region r1("R1");
    Region r2("R2");
    Region r3("R3");



    r1.addNeighbor(r2);
    r2.addNeighbor(r1);
    r2.addNeighbor(r3);
    r3.addNeighbor(r2);

    map.addRegion(r1);
    map.addRegion(r2);
    map.addRegion(r3);

    map.traversal(r1);
    map.isConnected();

    return 0;
}
下面是我的traversal()和isConnected()方法实现:

void Map::traversal(Region currentNode)
{
    visited.push_back(currentNode.getRegionName());
    Region* current = &currentNode;
    cout << (*current).getRegionName() << " loc: " << current << endl;
    for (auto const & neighbor : (currentNode).getNeighbors())
    {
        if (std::find(visited.begin(), visited.end(), neighbor.getRegionName()) != visited.end()) {
        }
        else {
            cout << (neighbor).getRegionName() << " neighbors: " << (neighbor).getNeighbors().size() << " location: " << &(neighbor) << endl;
            traversal(neighbor);
        }
    }
}

bool Map::isConnected()
{
    cout << visited.size() << endl;
    cout << regions.size() << endl;
    vector<string> regionList;

    for (int i = 0; i < regions.size(); i++)
    {
        regionList.push_back(regions[i].getRegionName());
    }
    if (visited.size() == regionList.size())
    {
        return true;
    }
    else
    {
        return false;
    }

}
void映射::遍历(区域currentNode)
{
push_back(currentNode.getRegionName());
区域*当前=¤tNode;
不能In

currentNode
按值传递。这意味着
currentNode
独立于调用
遍历时作为参数提供的
区域
的副本(无论在何处)。这是您注意到的不同地址

cout << (*current).getRegionName() << " loc: " << current << endl; 
虽然

void Map::traversal(const Region & currentNode)
如果您不打算更改函数内部的
currentNode
(或函数的结果),则首选此选项。它可以防止错误,而且由于您已承诺不更改提供的
区域
,编译器可以利用一些技巧和优化

下一个陷阱是

vector<Region> neighbors;
召唤

这也是传递值(
r
r2
的副本),并且

r
的副本放入向量中。最终结果是
r1
实际上不知道
r2
,它知道一个副本。在副本之后修改
r2
不会影响副本。您被捕获。您必须存储指针

该地区需要看起来更像

class Region
{
private:
    string owner;
    string regionName;
    int numTokens;
public:
    vector<Region *> neighbors; // change here
    void setOwner(string playerName);
    void setRegionName(string name);
    void setNumTokens(int num);
    void addNeighbor(Region * r); // change here
    vector<Region *> getNeighbors() const; // change here
    string getOwner() const;
    string getRegionName() const;
    int getNumTokens() const;
    Region();
    Region(string regionName);
    // ~Region(); not required.

};
是一个自动变量。它管理自己的生存期。当它超出范围时将被释放。您可以

r1.addNeighbor(&r2); //pass raw pointer to r2
而且
r2
将在
r1
之前按计划销毁,如果你认为这有点危险的话。
r1
仍然有一个指向
r2
的指针,但是
r1
也超出了范围,所以你需要在析构函数中做一些愚蠢的事情,或者使用多线程。
Region
不需要析构函数,所以您是安全的,如果您是多线程的,则需要一组全新的假设,例如为什么您在仍有线程运行的情况下超出了
main
的范围

但是,如果您添加和删除
Region
s并动态地重新塑造图形,那么不太重要的情况又如何呢

这很快就会变丑

通常,人们会选择在
邻居中使用智能指针来管理
他们的记忆力。在你的情况下不好用。在很多情况下也不好用

vector
(一个且只有一个指针)没有任何意义,因为可能有许多
区域
都指向同一
区域
。唯一性就到此为止

shared\u ptr
也没有意义,因为
r1
指向
r2
r2
指向
r1
。必须采取直接措施消除循环,这通常会破坏智能指针的指向。如果您忘记或因异常而脱轨,该怎么办

人们可以玩一些游戏,但在双向图中,谁是共享的,谁是弱者

意见警告:我赞成使用原始指针和
区域的主列表(
vector
,但这一次它仍然有效)作为图形类的成员,管理访问、插入、删除和所有其他操作,就像使用链表管理链接节点一样

可能有更尖锐的解决方案,我没有看到

编辑:这是一个基于M.M.的评论

class Region
{
private:
    string owner;
    string regionName;
    int numTokens;
public:
    vector<string> neighbors; // change here. If you have large numbers of neighbours 
                              // consider using a std::set in place of the vector
    void setOwner(string playerName);
    void setRegionName(string name);
    void setNumTokens(int num);
    void addNeighbor(const string & name); // change here. Accepting const reference 
                                           // reduces unnecessary copying. May want
                                           // to use the same trick for other methods 
                                           // receiving a string
    const vector<string> & getNeighbors() const; // change here. Returning const 
                                                 // reference reduces unnecessary copying
    string getOwner() const;
    string getRegionName() const;
    int getNumTokens() const;
    Region();
    Region(string regionName);
    // ~Region(); not required.

};
类区域
{
私人:
字符串所有者;
字符串regionName;
国际努姆托克斯;
公众:
向量邻居;//此处更改。如果有大量邻居
//考虑使用STD::设置代替矢量
void setOwner(字符串播放器名称);
void setRegionName(字符串名称);
void setNumTokens(int num);
void addNeighbor(常量字符串和名称);//在此处更改。接受常量引用
//减少不必要的复制。可能需要
//对其他方法使用相同的技巧
//接收字符串
常量向量&getNeights()const;//在此处更改。返回常量
//参考减少了不必要的复制
字符串getOwner()常量;
字符串getRegionName()常量;
int getNumTokens()常量;
区域();
区域(字符串regionName);
//~Region();不是必需的。
};
这假定
regionName
是唯一的,并将其用作从类似于
地图主列表的主列表中访问
区域的键;
主列表管理所有
区域的存储
。从中删除
区域,如果找不到
区域名
n
masterlist
您不必担心无效指针,只需记下并将其从
邻居中删除即可

请记住小心使用下标运算符。在
主列表[名称]
中,如果找不到
名称
,则默认为其构造并存储一个
区域
。如果要查找应该存在的
区域
,请使用
查找
方法

如果您有固定数量的区域,请考虑使用一个简单的数组或<代码> STD::数组< /COD>代替<代码> MAP>代码> > <代码> MistList< /Cord>,并使用数组中的<代码>区域< /代码>的索引作为标识符代替代码>字符串< /代码> .< 补充阅读:

你可能会发现
vector<Region> neighbors;
r1.addNeighbor(r2);
void Region::addNeighbor(Region r)
neighbors.push_back(r);
class Region
{
private:
    string owner;
    string regionName;
    int numTokens;
public:
    vector<Region *> neighbors; // change here
    void setOwner(string playerName);
    void setRegionName(string name);
    void setNumTokens(int num);
    void addNeighbor(Region * r); // change here
    vector<Region *> getNeighbors() const; // change here
    string getOwner() const;
    string getRegionName() const;
    int getNumTokens() const;
    Region();
    Region(string regionName);
    // ~Region(); not required.

};
Region r1("R1");
r1.addNeighbor(&r2); //pass raw pointer to r2
class Region
{
private:
    string owner;
    string regionName;
    int numTokens;
public:
    vector<string> neighbors; // change here. If you have large numbers of neighbours 
                              // consider using a std::set in place of the vector
    void setOwner(string playerName);
    void setRegionName(string name);
    void setNumTokens(int num);
    void addNeighbor(const string & name); // change here. Accepting const reference 
                                           // reduces unnecessary copying. May want
                                           // to use the same trick for other methods 
                                           // receiving a string
    const vector<string> & getNeighbors() const; // change here. Returning const 
                                                 // reference reduces unnecessary copying
    string getOwner() const;
    string getRegionName() const;
    int getNumTokens() const;
    Region();
    Region(string regionName);
    // ~Region(); not required.

};