Как создавать цепочки указателей? Я хотел бы создать объекты, которые имеют указатели, указывающие на другие объекты, которые имеют указатели. Это вообще возможно? - PullRequest
0 голосов
/ 07 января 2020

Я создал этот пример кода, но я просто не могу заставить его работать. Я хочу создать дочерние элементы из родительского узла таким образом, чтобы у каждого дочернего элемента был один родительский элемент, и у каждого был указатель на его родительский узел. Указатель первого родителя является нулевым указателем. Теперь возникает вопрос: если я где-то в конце ветви дерева, как я могу шаг за шагом вернуться к первому родительскому элементу и выписать историю?

В этом примере для простоты Я создал линейный график с одним простым путем.

Я обнаружил, что если я хочу разыменовать узел родительского узла во второй раз, я уже получаю поддельные результаты и не могу достичь дальше, чем Первый родитель. Поэтому я могу только разыменовать родительский узел текущего узла. Это почему? Я видел, что в связанных списках люди хранят каждый указатель, но я бы хотел этого избежать. Цель состоит в том, чтобы каждый узел хранился в list<Node>, и каждый из них хранит только указатель своего родителя, поэтому по каждому узлу мы можем отследить первого родителя.

#include <iostream>
#include <list>

using namespace std;

struct Node
{
    int node;
    Node *parent;
};

void create (Node parent, list<Node>& graph)
{
    if (graph.size() < 10)
    {
        Node nn;
        nn.node = parent.node+1;
        nn.parent = &parent;
        graph.push_back(nn);
        create(nn, graph);
    }
}

int main()
{
    list<Node> graph;

    Node parent;
    parent.node = 0;
    parent.parent = nullptr;
    graph.push_back(parent);

    create(parent, graph);

    for (auto i : graph)
    {
        cout << i.node << " ";
    }
    cout << endl << endl;

    auto it = graph.begin();
    advance(it, 3);

    cout << (*it).node << endl;
    cout << (*(*(*it).parent).parent).node;

    return 0;
}

1 Ответ

0 голосов
/ 07 января 2020

Вы создаете Node s как локальные переменные в функции create. Когда вы выходите из области действия функции, адреса, которые вы сохраняете как Node s 'parent, не будут содержать Node, который был там ранее (каждый nn.parent становится висящим указателем ).

Если вы хотите sh создать Node s в функции, она должна выглядеть примерно так:

void create(Node* parent, list<Node>& graph)
{
    if (graph.size() < 10)
    {
        Node* nn = new Node;
        nn->node = parent->node + 1;
        nn->parent = parent;
        graph.push_back(*nn);
        create(nn, graph);
    }
}

Это, однако, вызовет несколько проблем:

  1. В этой строке graph.push_back(*nn); мы разыменовываем nn, что приводит к ненужному копированию значений int и Node* (атрибуты структуры).
  2. Мы вызываем утечку памяти, поскольку мы не являемся сохраняя значение nn в любом месте, поэтому мы не сможем удалить его содержимое позже.

Было бы лучше сохранить список Node* вместо Node:

list<Node*> graph;

Таким образом, мы могли бы просто выполнить итерацию по списку и позже удалить динамически выделенные Node s:

for (auto i : graph)
    delete i;

И вместо копирования значений int и Node*, мы просто pu sh Node* nn к списку:

graph.push_back(nn);

Обратите внимание, что it теперь является указателем на указатель, поэтому потребуется двойное разыменование:

cout << (**it).node << endl;
cout << (*(*(**it).parent).parent).node;
...