按值与按引用读取C++向量


这是一个

基本的指针问题,但这让我困惑了一段时间。我已经实现了一个加权图,使用 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);

您正在获得对该向量的引用。

如果将元素添加到副本,

则它们将不会添加到地图中(因为它只是一个副本,不再与原始元素有任何关系)。如果将元素添加到引用中,则会将其添加到地图中,因为它是相同的矢量。

最新更新