数据模型,循环引用

时间:2010-09-09 13:50:54

标签: c++ copy-constructor datamodel cyclic-reference

我有以下数据结构用于存储经络和平行线。

每个制图点存储:
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并用new替换旧点和链接,这不是一个实现问题......但是指针从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 个答案:

答案 0 :(得分:2)

  

有人会帮我改进吗?

在这种情况下,我通常采用这样的方式:

 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对象都是唯一的,如果不是,则重用现有对象的id。 / p>

本质上是寻址方案,为每个节点提供唯一的全局标识符。不是最好/最简单的解决方案,有一个全球容器,但不止一次帮助了我。特别是为了避免内存泄漏并确保清除破坏相互依赖对象的整个层次结构。

除了typedef int node_id_t之外,还可以使用struct node_id_t { int id; };和重载转换运算符来简化节点ID查找。

答案 1 :(得分:0)

在我看来,在某些情况下用指数替换指针的解决方案会很慢。

  • 如果我们不删除任何一点,则point_id将代表他的指数,例如。节点[poin_id],没关系。

  • 但是如果我们删除列表中的任何一点,则point_id将不代表列表中的索引。我们将不得不使用std :: find并获得找到点的point_id。这大大降低了代码的速度......

  • 如果我们删除任何一点,我们可以重新索引点列表以避免上述问题。但是我们不必忘记重新索引所有meridinans的开始/结束索引......但它需要一些时间并且与问题中的复制构造函数相同。而且我认为,使用复制构造函数影响某个类的数据的另一个类表示不太适合数据结构的提议......