2013-08-06 2 views
1

У меня есть несколько различных типов классов, которые связаны друг с другом (они содержат указатели друг на друга - некоторые из них - векторы указателей), и я очень доволен этим дизайном. Но теперь наступает момент, когда я хотел бы сделать копию всей моей структуры и очень сложно исправить все ссылки каждого экземпляра новых классов. У меня уже есть класс контейнера для всей структуры, но все же попытки, которые я сделал для написания метода clone(), оказались в очень грязном коде, и я не удовлетворен ими.классы копирования связаны между собой

Я хотел бы знать, есть ли какой-то шаблон дизайна, который мог бы помочь решить эту проблему.

+0

Это совершенно невозможно, не видя ваш дизайн; ваше описание очень неопределенно – nijansen

+0

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

+0

Пожалуйста, разместите хотя бы некоторый исходный код, по крайней мере, для пары классов, которые у вас есть, и как они связаны друг с другом. – JoshG79

ответ

1

Одно из решений, которые могли бы помочь вам (если я правильно понял из вашего довольно расплывчатого описания):

  1. создать клон всех ваши объектов (в настоящее время, просто скопировать все указатели на новые объекты по-прежнему указывая на исходные объекты)
  2. при этом отслеживать, какой объект является клоном того или иного объекта в каком-то словаре (что-то вроде std::map<void*,void*> должно выполнять эту работу, но, может быть, вы можете придумать что-то лучшее, чем уродливое void*)
  3. пройти все новые объекты и перенаправить все указатели по значениям, хранящимся в словаре
+0

Да, карты - это моя последняя попытка решить проблему, на самом деле тот, кто заставил меня спросить здесь! Это, наверное, не так уж плохо, мне просто нужно больше работать над этим, потому что топология сложна, и я просто не могу иметь очень чистый и простой код. – DarioP

1

Обычный подход заключается в том, чтобы сохранить какую-то форму отображения от старых к новым указателям - перед созданием копии проконсультируйтесь с картой, чтобы узнать, был ли объект уже скопирован, и если это, вернуть существующую копию, иначе, call clone().

Что-то вроде этого:

#include <unordered_map> 
#include <vector> 

typedef std::unordered_map<void *, void *> map_type; 

template<typename T> 
T *clone (T *ptr, map_type &m) 
{ 
    auto p = m.find (ptr); 
    if (p != m.end()) 
    return static_cast<T *> (p->second); 
    else 
    return ptr->clone (m); 
} 

struct S 
{ 
    int x; 
    std::vector<S *> v; 

    S *clone (map_type &m) 
    { 
    S *p = new S; 

    // this is important to happen before calling clone() on subobjects 
    m [this] = p; 

    p->x = x; 
    for (auto q: v) 
     p->v.push_back (::clone (q, m)); 

    return p; 
    } 
}; 

int 
main() 
{ 
    S *p = new S(); 
    p->x = 1; 

    S *q = new S(); 
    q->x = 2; 

    S *r = new S(); 
    r->x = 3; 

    p->v.push_back (p); 
    p->v.push_back (p); 
    p->v.push_back (q); 

    q->v.push_back (p); 
    q->v.push_back (r); 

    r->v.push_back (p); 

    map_type m; 

    S *x; 
    x = clone (p, m); 
} 
+0

+1 для 'unordered_map', я об этом не думал! – DarioP

0

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

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

Это позволит масштабировать/добавлять новые компоненты без изменения большей части кода.

+0

Иерархия почти есть, но проблема в том, что у «внуков» есть два родителя. Вероятно, это было бы довольно легко. У меня уже есть «родитель всего», мне просто нужно выяснить, как позволить ему делать грязную работу :) – DarioP

+0

Почему у внуков есть два родителя - вы имеете в виду, что у каждого внука есть родитель и дедушка?Если это так, родитель заботится обо всех своих детях, в то время как каждый ребенок, в свою очередь, заботится обо всех своих детях - родитель не должен знать, имеет ли ребенок других детей, ребенку не нужно знать, имеет ли родитель других родителей. У ребенка должен быть метод клонирования или что-то в этом роде, что он может распространять дальше всех своих собственных детей и рекурсивно возвращать все, что требуется. Идея концепции состоит в том, чтобы использовать рекурсию и не содержать никакой информации о других родительских отношениях с прямым родителем. –

+0

Топология более или менее напоминает дерево: с логом, ветвями и листьями, где один и тот же лист появляется на двух ветвях одновременно (таким образом, у него есть два родителя). Но я не хочу тратить свое время, я должен был получить достаточное количество намеков для завершения кода. – DarioP

Смежные вопросы