Модель данных, циклические ссылки - PullRequest
1 голос
/ 09 сентября 2010

У меня есть следующая структура данных для хранения меридианов и параллелей.

Каждый картографический пункт хранит:
A] географические и пространственные координаты, картографические искажения и т. Д.
B] указатель на север / юг / восток / западный узел.

Позволяет хранить отношения между точками, прежде всего их принадлежность к меридиан / параллель ...

 class Node2DCart 
 { 
     protected: 
             //Coordinates of the point 
             double lat; 
             double lon; 
             double lattrans; 
             double lontrans; 
             double x; 
             double y; 
 ..... 
             //Pointers to adjacent points in geographic network 
             Node2DCart *left; 
             Node2DCart *right; 
             Node2DCart *top; 
             Node2DCart *bottom; 
 ..... 
 }; 

Структура данных для меридиана хранит долготу меридиана, начало точка и конечная точка меридиана и количество точек.

 class Meridian 
 { 
     private: 
             unsigned int points_count; 
             double longitude; 
             Node2DCart *start; 
             Node2DCart *end; 
 .... 
 }; 

Все точки хранятся в списке узлов:

typedef std::vector<Node2DCart*> TNodes2DCartList; 

class Node2DCartList 
{ 
     protected: 

             TNodes2DCartList nodes; 

     ... 
}; 

Но существует большая проблема при написании конструктора копирования для Node2DList. Между Meridian / Parallel и Node2Dlist существует циклическая зависимость.

Конструктор копирования использует std::map и заменяет старые точки и ссылки новыми, это не проблема реализации ... Однако указатели начинаются / заканчиваются от точки класса Meridian до точек из старого Node2DList ... Конструктор копирования Node2DList должен уведомить все меридианы, указывающие на старые точки Node2DList, и изменить все указатели на новые точки Node2DList. Эта модель не позволяет этого.

Возможным решением было бы добавление двух указателей, указывающих на меридиан, и параллельная точка принадлежит:

 class Node2DCart 
 { 
     protected: 
             //Coordinates of the point 
             double lat; 
             double lon; 
             double lattrans; 
             double lontrans; 
             double x; 
             double y; 
 ..... 
             //Pointers to adjacent points in geographic network 
             Node2DCart *left; 
             Node2DCart *right; 
             Node2DCart *top; 
             Node2DCart *bottom; 
 ..... 
             Meridian *m;
             Parallel *p;
 };

Боюсь, что эта предложенная модель не годится. Между двумя классами все еще есть циклические ссылки ... Кто-нибудь поможет мне улучшить его? Спасибо ...

Ответы [ 2 ]

2 голосов
/ 09 сентября 2010

Кто-нибудь поможет мне улучшить его?

В таких случаях я обычно прибегаю к чему-то вроде этого:

 typedef int node_id_t;
 enum { NODE_NULL = 0 };
 // or enum node_id_t { NODE_NULL=0 }; for strict typing.

 class Node2DCart 
 { 
     protected:
             node_id_t id;    // id of the node
             //Coordinates of the point 
             double lat; 
             double lon; 
             double lattrans; 
             double lontrans; 
             double x; 
             double y; 
 ..... 
             //Pointers to adjacent points in geographic network 
             node_id_t left;
             node_id_t right; 
             node_id_t top; 
             node_id_t bottom; 
 ..... 
 };

 class Meridian
 {
     private:
             unsigned int points_count;
             double longitude;
             node_id_t start;
             node_id_t end;
 .... 
 };

 /* ... */

 std::vector<Node2DCart *> node_registry;

 // during initialization:
 node_registry.push_back( NULL );
 // to reserve 0th element to denote the NULL pointer

 Node2DCart *
 GetNode(node_id_t id)
 {
    // placeholder of the id range check
    return node_registry[id];
 };

 node_id_t
 AddNode(Node2DCart *n)
 {
    node_registry.push_back(n);
    return node_id_t(node_registry.size()-1);
 };

И затем использую числовое значение node_id_t вместо Node2DCart *.Можно также добавить std::set (или std::map, обновленный / протестированный в AddNode()), чтобы гарантировать, что все объекты Node2DCart являются уникальными и, если нет, повторно использовать идентификатор существующего объекта.

По существу схема адресации , предоставляющая каждому узлу уникальный глобальный идентификатор.Не самое хорошее / простое решение с глобальным контейнером, но помогло мне не раз.Особенно, чтобы избежать утечек памяти и обеспечить чистое разрушение всей иерархии взаимозависимых объектов.

Вместо typedef int node_id_t можно также использовать struct node_id_t { int id; }; и операторы преобразования перегрузки для упрощения поиска идентификаторов узлов.

0 голосов
/ 09 сентября 2010

По моему мнению, решение о замене указателей на индексы в некоторых случаях будет медленным.

  • Если мы не удаляем ни одну точку, point_id будет представлять индекс точки, например. узлы [poin_id], все в порядке.

  • Но если мы удалим какую-либо точку списка, point_id не будет представлять его индекс в списке. Мы должны будем использовать std :: find и получить point_id найденной точки. Это значительно снижает скорость кода ...

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

...