Глубокая копия древовидной структуры данных на С++ без шаблонного кода копирования?

Предположим, у меня есть древовидная структура данных, реализованная с помощью класса node:

class Node
{
  Node * parent;
  std::vector<Node*> children;
  int data_1;
  std::string data_2;
  double data_3;
  ...
  float data_n;
};

Чтобы сделать глубокую копию, есть ли способ обойти запись всего шаблонного копирования для свойств не указателя? Все из

that.data_1 = this->data_1;
that.data_2 = this->data_2;
...
that.data_n = this->data_n;

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

(Я готов использовать С++ 11 и с меньшим энтузиазмом повышать)


person Alec Jacobson    schedule 05.05.2014    source источник
comment
Вы можете обернуть все не указатели в структуру, а затем просто скопировать структуру. Однако добавил бы дополнительную точку ко всем доступам. В качестве альтернативы можно обернуть указатели в подструктуру и дать ей собственный конструктор копирования.   -  person dlf    schedule 06.05.2014
comment
аналогичноstd::tuple, вероятно, можно было бы использовать, но это также усложнило бы доступ к данным.   -  person YoungJohn    schedule 06.05.2014
comment
Обертывание указателей в структуру или класс также может помочь вам разделить ваши проблемы. В конце концов, если все указатели связаны (т. е. используются для обхода узла), объединение их вместе может позволить вам передать их функциям или алгоритмам, которые не заботятся об остальных данных.   -  person YoungJohn    schedule 06.05.2014


Ответы (3)


Как указано в комментариях, вы можете обернуть данные в структуру, затем просто скопировать структуру и обработать остальную часть процесса копирования в теле конструктора копирования:

class Node
{
  Node * parent;
  std::vector<Node*> children;
  //... maybe more

  struct Data {
      int data_1;
      std::string data_2;
      double data_3;
      ...
      float data_n;
  }
  Data data;
  Node( Node const& other) : data( other.data) {
      //... do the rest
  }
};
person 4pie0    schedule 05.05.2014
comment
Хороший. Таким образом, это решение влечет за собой дополнительную точку для доступа: my_node->data_1 становится my_node->data.data_1? - person Alec Jacobson; 06.05.2014
comment
Есть ли способ создать шаблон и для получения такого класса? Создание шаблонов на Data кажется простым, но я не могу представить, как получить производный от Node, поскольку производный класс должен иметь производный класс children, поэтому я не могу выполнять неприятную часть глубокого копирования внутри Node. (Почему реализация дерева с родительскими указателями так неуловима? Или все поддерживают стандартное копирование и op= подпрограммы?) - person Alec Jacobson; 24.10.2014

Вы можете поместить полезную нагрузку в базовый класс:

struct i {
        i(int a, float b) : a(a), b(b) {}
        int a;
        float b;
};

struct n : i {
        using i::i;
        n(const n&r) : i(r) {}
};

n N {1,1.0};

int main()
{
        n M {0,1.0};
        M=N;
        return M.a;
}

у которого есть и другие преимущества, я полюбил отделять контент от структуры.

person jthill    schedule 05.05.2014
comment
наследование следует использовать для выражения является своего рода отношением. По крайней мере, в этом случае следует использовать частное наследование. - person 4pie0; 06.05.2014
comment
@privatedatapublicchannel2 Это странное ограничение. Не могу сказать, что вижу какую-либо ценность в категорическом запрете CRTP и всех подобных методов. Мне кажется, вы глубоко погрузились в не проще территорию. (изменить: заменить искаженную ссылку после 5-минутного лимита, поэтому переписал). - person jthill; 06.05.2014

Если вам нужен только рекурсивный контейнер, вы можете использовать Boost.Container. Он разработан с учетом этих вариантов использования. Проблема, которую я вижу в вашем коде, - это указатель на родителя. Я думаю, что это не может быть просто реализовано. Но вы получите управление памятью бесплатно.

person Jan Herrmann    schedule 06.05.2014
comment
Если мне не нужен родительский указатель, действительно ли мне нужны буст-контейнеры? Контейнеров stl недостаточно? - person Alec Jacobson; 24.10.2014
comment
@mangledorf нет. См. stackoverflow.com/questions/ 18672135/ и boost.org/doc/libs/1_55_0/doc/html/container/ . Пока вам нужны рекурсивные контейнеры, у вас есть неполный тип. - person Jan Herrmann; 24.10.2014