Как скопировать связанные классы

0

Я хочу иметь общие переменные, которые я могу легко написать/загрузить из файла XML и, возможно, использовать в системе меню. Класс, содержащий такие переменные, будет выглядеть так:

class Entity
{
private:
 VarGroup group;

 Var<float> myfloat;
 Var<int> myint;

public:
 Entity() : group("group name"), myfloat("name", &group), myint("name2", &group) {}
};

Var оснащен перегруженными операторами, поэтому я могу использовать их как обычные переменные. Им даются буквальные имена, а их указатели базового класса вставляются в группу. VarGroup используется для выполнения VarGroup действий по типам Var, таким как импорт в/из XML.

Проблема в том, что если объекты Entity хранятся в std::vector по значению, данные могут перемещаться в памяти, а указатели Var в объекте VarGroup становятся недействительными.

Возможно или даже разумно попытаться обработать этот тип копии по функциональности в Var и VarGroup?

Подробнее:

class VarBase
{
protected:
 std::string name;

public:
 VarBase(const std::string &_name) : name(_name) {}
 virtual bool toXMLNode(rapidxml::xml_document<> *doc, rapidxml::xml_node<> *parent) const = 0;
 virtual bool fromXMLNode(rapidxml::xml_node<> *node) = 0;
 std::string getName() const;
};

class VarGroup
{
private:
 std::string name;
 std::vector<VarBase*> vars;

public:
 VarGroup(const std::string &_name) : name(_name) {}

 void insert(VarBase *var)
 {
  vars.push_back(var);
 }

 bool toXMLNode(const std::string &nodeName, rapidxml::xml_document<> *doc) const;
 bool fromXMLNode(rapidxml::xml_node<> *node);
};

template<typename T>
class Var : public VarBase
{
private:
 T value;

public:
 Var(const std::string &_name, VarGroup *group) : VarBase(_name)
 {
  group->insert(this);
 }

 bool toXMLNode(rapidxml::xml_document<> *doc, rapidxml::xml_node<> *parent) const override;
 bool fromXMLNode(rapidxml::xml_node<> *node) override;

 // Implementations of operators (), =, etc.
};
  • 0
    Проблемная область называется сериализацией. Посмотрите на boost :: serialization.
  • 1
    Может быть, вы могли бы сделать так, чтобы VarGroup действительно владел данными, например, будучи контейнером уникальных указателей?
Показать ещё 4 комментария
Теги:

1 ответ

0

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

Я добавил указатель VarGroup к классу Var, чтобы сделать два связанных в обоих направлениях. Затем я добавил конструкторы копирования, которые пытаются сохранить правильную связь под копией любого класса, и это должно быть независимым от порядка.

class VarBase
{
protected:
 std::string name;

public:
 VarBase(const std::string &_name) : name(_name) {}
 virtual bool toXMLNode(rapidxml::xml_document<> *doc, rapidxml::xml_node<> *parent) const = 0;
 virtual bool fromXMLNode(rapidxml::xml_node<> *node) = 0;
 std::string getName() const;
};

class VarGroup
{
private:
 std::string name;
 std::vector<VarBase*> vars;

public:
 VarGroup(const std::string &_name) : name(_name) {}

 VarGroup(const VarGroup &that)
 {
  name = that.name;
  vars = that.vars;

  for(auto base : vars)
   base->pGroup = this;
 }

 // Swap existing VarBase pointer with new one.
 void swap(VarBase *newVar, VarBase *oldVar)
 {
  auto it = find(vars.begin(), vars.end(), oldVar);
  *it = newVar;
 }

 void insert(VarBase *var)
 {
  vars.push_back(var);
 }

 bool toXMLNode(const std::string &nodeName, rapidxml::xml_document<> *doc) const;
 bool fromXMLNode(rapidxml::xml_node<> *node);
};

template<typename T>
class Var : public VarBase
{
friend class VarGroup;
private:
 T value;
 VarGroup *pGroup;

public:
 Var(const std::string &_name, VarGroup *_pGroup) : VarBase(_name), pGroup(_pGroup)
 {
  pGroup->insert(this);
 }

 Var(const Var &that)
 {
  pGroup = that.pGroup;
  value = that.value;

  pGroup->swap(this, &that);
 }

 bool toXMLNode(rapidxml::xml_document<> *doc, rapidxml::xml_node<> *parent) const override;
 bool fromXMLNode(rapidxml::xml_node<> *node) override;

 // Implementations of operators (), =, etc.
};

Теперь есть два экземпляра копии:

1) Объект VarGroup сначала копируется.

Он обращается к "скопированным" объектам Var чтобы изменить их указатель на новую. Когда объекты Var копируются, они копируют новый адрес VarGroup из старого объекта Var. Затем с помощью этого нового указателя они вызывают новый объект VarGroup чтобы изменить свой старый адрес объекта Var на новый.

2) Сначала объекты Var копируются.

Конструктор копирования копирует старый групповой адрес (избыточная операция). Затем он меняет адрес Var из "скопированной группы". Когда объект VarGroup копируется, он уже имеет новые адреса Var (если все объекты Var были скопированы). Затем он обращается к новым объектам Var чтобы изменить их указатель на новую.

Это звучит слишком сложно, но может ли это сработать?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню