C++ 循环遍历C+中类中包含的向量+;不复制影响值?
我正在尝试编写一个算法来检查一个图是否是连通的(构建一个棋盘游戏,其中地图包含为一个图,其中区域是顶点,边界是边) 每个区域都包含一个作为其邻居的区域向量(向量邻居) 我在main()函数中构建映射并检查其是否连接: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);
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 = ¤tNode;
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
是唯一的,并将其用作从类似于地图主列表的主列表中访问区域的键;
主列表管理所有区域的存储。从中删除区域,如果找不到区域名
nmasterlist
您不必担心无效指针,只需记下并将其从邻居中删除即可
请记住小心使用下标运算符。在主列表[名称]
中,如果找不到名称
,则默认为其构造并存储一个区域
。如果要查找应该存在的区域
,请使用查找
方法
如果您有固定数量的区域,请考虑使用一个简单的数组或<代码> 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.
};