C ++ передача указателя от конструктора к конструктору - PullRequest
0 голосов
/ 27 мая 2018

Я работаю над изучением C ++ и создал 3 класса: NodeEditor, Node, NodeIO.

По сути, редактор содержит вектор узлов, каждый из узлов имеет вектор экземпляров NodeIO.

Я хочу, чтобы каждый класс мог ссылаться на него "владелец".

По сути, конструктор NodeIO получает указатель от узла In-In, узел принимает указатель на свой редактор.

class NodeEditor {
    NodeEditor() {
        ...push_back(Node(this));
    }
}

class Node {
    NodeEditor* owner;
    Node(NodeEditor* _owner) : owner{ _owner } {
        ...push_back(NodeIO(this));
    }
}

class NodeIO {
    Node* owner;
    NodeIO(Node* _owner) : owner{ _owner } { }
}

Затем мне нужно использовать указатели _owner.

Когда я пытаюсь сделать это в моем проекте, сначала указатель _owner указывает на правильное местоположение,но как только мне потребуется извлечь его позже, фактический объект больше не будет существовать в этом месте указателей.

Какие варианты я могу разрешить для работы такого типа макета?И есть ли другой, более рекомендуемый шаблон, которому нужно следовать в этой ситуации.

Ответы [ 3 ]

0 голосов
/ 27 мая 2018

Вы не показали никаких конструкторов копирования.Таким образом, я предполагаю, что вы полагаетесь на конструкторы копирования по умолчанию, предоставленные компилятором.Это источник вашей проблемы.

Когда вы используете:

    ...push_back(Node(this));

в NodeEditor, вы сохраняете копию Node(this).Однако, если Node и NodeIO не имеют правильно реализованных конструкторов копирования, объекты NodeIO в объекте Node в std::vector будут указывать на недопустимый объект Node -временный Node объект.


Вот пример программы, которая показывает проблему.

#include <iostream>
#include <vector>

struct Node;

struct NodeIO {
   Node* owner;
   NodeIO(Node* _owner) : owner{ _owner } { }
};

struct NodeEditor;

struct Node {
   NodeEditor* owner;
   Node(NodeEditor* _owner) : owner(_owner)
   {
      std::cout << (void*)this << std::endl;
      nodeIOList.push_back(NodeIO(this));
      nodeIOList.push_back(NodeIO(this));
   }

   std::vector<NodeIO> nodeIOList;
};

struct NodeEditor {
   NodeEditor()
   {
      nodeList.push_back(Node(this));
      nodeList.push_back(Node(this));
   }
   std::vector<Node> nodeList;
};

int main()
{
   NodeEditor editor;
   for ( auto& node : editor.nodeList )
   {
      std::cout << (void*)(&node) << std::endl;
      for (auto& nodeIO : node.nodeIOList )
      {
         std::cout << (void*)(nodeIO.owner) << std::endl;
      }
   }
}

Вывод:

0x7ffe53d34c30
0x7ffe53d34c50
0xae10c0
0x7ffe1af7a2a0
0x7ffe1af7a2a0
0xae10e0
0x7ffe1af7a2c0
0x7ffe1af7a2c0

Вывод ясно показывает значенияиз указателей на Node объекты, которые были построены с использованием Node(this), и значений указателей на Node объектов, которые хранятся в std::vector<Node>.Обратите внимание, что объекты NodeIO по-прежнему указывают на временные объекты Node.Они указывают на main.


Я попытался быстро исправить, но это не сработало.Мне нужно немного поработать над этим.


Вот решение, которое работает с конструкторами копирования по умолчанию.Он использует std::vector из std::shared_ptr с вместо std::vector объектов.

#include <iostream>
#include <vector>
#include <memory>

struct Node;

struct NodeIO {
   Node* owner;
   NodeIO(Node* _owner) : owner{ _owner } { }
};

struct NodeEditor;

struct Node {
   NodeEditor* owner;
   Node(NodeEditor* _owner) : owner(_owner)
   {
      std::cout << (void*)this << std::endl;
      nodeIOList.push_back(std::make_shared<NodeIO>(this));
      nodeIOList.push_back(std::make_shared<NodeIO>(this));
   }

   std::vector<std::shared_ptr<NodeIO>> nodeIOList;
};

struct NodeEditor {
   NodeEditor()
   {
      nodeList.push_back(std::make_shared<Node>(this));
      nodeList.push_back(std::make_shared<Node>(this));
   }
   std::vector<std::shared_ptr<Node>> nodeList;
};

int main()
{
   NodeEditor editor;
   for ( auto& node : editor.nodeList )
   {
      std::cout << (void*)(node.get()) << std::endl;
      for (auto& nodeIO : node->nodeIOList )
      {
         std::cout << (void*)(nodeIO.get()->owner) << std::endl;
      }
   }
}

Вывод:

0x1460c30
0x1461110
0x1460c30
0x1460c30
0x1460c30
0x1461110
0x1461110
0x1461110
0 голосов
/ 27 мая 2018

Когда вы добавляете вещи в вектор, возможно, что все элементы вектора перемещаются.Таким образом, при добавлении Node возможно, что все существующие указатели владельца NodeIO s станут недействительными.

Чтобы справиться с этим, вам необходимо либо

  • Используйте другую структуру данных и отключите конструкторы копирования и перемещения Node или
  • В конструкторе перемещения Node обновите указатели owner всех содержащихся в нем NodeIO, иубедитесь, что новые NodeIO созданы правильно, если вы вызываете конструктор копирования Node.

В зависимости от того, как вы храните NodeEditor s, вам, вероятно, следует сделать то же самое с ними.

0 голосов
/ 27 мая 2018

Проверка времени жизни объектов NodeEditor, объектов Node и NodeIo.Используйте оператор new для создания динамических объектов или убедитесь, что создание экземпляров NodeEditor и Node и NodeIo происходит в одной и той же области видимости.Проверьте, храните ли вы копию Node-контейнера объекта NodeEditor и используете ли вы ее после освобождения объекта NodeEditor.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...