基本的指针问题,但这让我困惑了一段时间。我已经实现了一个加权图,使用 C++ map
作为底层数据结构,如下所示:
std::map<int, std::vector<Edge> > edgeList;
此映射将节点 id(int
)作为键,并使用vector
作为值保存此节点上的边列表
我已经初始化了每个节点的边缘列表,如下所示:
for(int i = 0; i< n; i++){
std::vector<Edge> vi;
edgeList.insert(std::make_pair(i,vi)); // initialize with empty vector (at least, that's the intent)
}
现在,在向图形添加边缘时,当我尝试检索对应于每个节点的边缘列表vector
如下所示:
std::vector<Edge> vList = edgeList.at(v); // v is the node id here
返回一个空的 vector
vList,即使我之前已经向该 vList 添加了边缘。
另一方面
std::vector<Edge> &vList = edgeList.at(v);
似乎对我的目的工作正常。谁能解释一下为什么第一个实现不起作用而第二个实现不起作用?
编辑:用于向图形添加边缘的代码如下所示:
void Graph::addEdge(Edge e){
// retrieve start and end node for this edge
int v = e.either(); // returns either end of the edge
int w = e.other(v);
// retrieve edge lists for these nodes
std::vector<Edge> vList = edgeList.at(v); // doesn't work
std::vector<Edge> wList = edgeList.at(w); // doesn't work
// add this edge to the list of edges
vList.push_back(e);
wList.push_back(e);
}
std::map::at
函数返回对给定索引处std::vector
的引用。当您将其分配给非引用变量时,您将创建向量的副本。您执行的任何插入操作都将在向量的副本上,该副本在方法结束时超出范围,而您瞄准的向量只是愉快地位于映射中,不受影响。
相反,如果添加&
,则vList
将真正成为存储在地图中的实际矢量的别名。现在,对vList
所做的任何更改实际上都是对 map 元素进行的。如果您愿意,可以将引用视为伪装的指针。在这种情况下,您将明确编写
std::vector<Edge> *vList = &edgeList.at(v);
而不是,例如,
std::vector<Edge> *vList = new std::vector();
*vList = edgeList.at(v);
实际上,以下示例更清楚地说明了这一点:
using namespace std;
int i = 0;
int& get_i()
{
return i;
}
int main()
{
cout << "i = " << i << ", &i = " << &i << endl;
int j = get_i();
j++;
cout << "i = " << i << ", j = " << j << ", &j = " << &j << endl;
int& k = get_i();
k++;
cout << "i = " << i << ", k = " << k << ", &k = " << &k << endl;
return 0;
}
当你这样做时:
std::vector<Edge> vList = edgeList.at(v);
您正在地图中创建矢量的副本。
执行此操作时:
std::vector<Edge> &vList = edgeList.at(v);
您正在获得对该向量的引用。
如果将元素添加到副本,则它们将不会添加到地图中(因为它只是一个副本,不再与原始元素有任何关系)。如果将元素添加到引用中,则会将其添加到地图中,因为它是相同的矢量。