Вопрос

Это фундаментальный вопрос с указателем, но это на некоторое время сбивает с толку. Я реализовал взвешенный график, используя C ++ map в качестве основной данные о данных следующим образом:

std::map<int, std::vector<Edge> > edgeList;

Эта карта содержит идентификатор узла ( 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 действительно сделаны в элементе карты. Если хотите, вы можете посмотреть на ссылку в качестве замаскированного указателя. В этом случае вы явно напишите

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);

Вы получаете ссылку на этот вектор.

Если вы добавите элементы в копию, они не будут добавлены на карту (так как это просто копия и больше не имеет отношения к оригиналу). Если вы добавите элементы в ссылку, он добавлен к карте, потому что это тот же вектор.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top