Linux 数据模型,循环引用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3677181/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 23:23:34  来源:igfitidea点击:

Data model, cyclic references

c++copy-constructordatamodelcyclic-reference

提问by Robo

I have the following data structure for storing meridians and parallels.

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

Each cartographic point stores:
A] geographic and spatial coordinates, cartographic distortions, etc.
B] pointer to north/south/east/west node.

每个制图点存储:
A] 地理和空间坐标、制图失真等。
B] 指向北/南/东/西节点的指针。

It allows to store relationships between points, first of all their affiliation to the meridian/parallel...

它允许存储点之间的关系,首先它们与子午线/平行...

 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; 
 ..... 
 }; 

Data structure for meridian stores longitude of the meridian, start point and end point of the meridian and number of points.

子午线的数据结构存储子午线的经度、子午线的起点和终点以及点数。

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

All points are stored in nodes list:

所有点都存储在节点列表中:

typedef std::vector<Node2DCart*> TNodes2DCartList; 

class Node2DCartList 
{ 
     protected: 

             TNodes2DCartList nodes; 

     ... 
}; 

But there is a big problem writing copy constructor for Node2DList. There is a cyclic dependency between Meridian/Parallel and Node2Dlist.

但是为 Node2DList 编写复制构造函数有一个大问题。Meridian/Parallel 和 Node2Dlist 之间存在循环依赖。

Copy constructor uses std::mapand replaces old points and links with new, it is not an implementation problem... However pointers start/end from class Meridian point to points from old Node2DList... Node2DList copy constructor should have to notify all meridians pointed to old Node2DList points and change all pointers to new Node2DList points. This model does not allow it.

复制构造函数使用std::map新的点和链接替换旧的点和链接,这不是实现问题...但是,从类 Meridian 开始/结束的指针指向旧 Node2DList 的点... Node2DList 复制构造函数应该通知所有指向旧的子午线Node2DList 指向并将所有指针更改为新的 Node2DList 点。这个模型不允许。

The possible solution would be adding two pointers pointing to meridian and parallel point belongs to:

可能的解决方案是添加两个指向子午线和平行点所属的指针:

 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;
 };

I am afraid that this proposed model is not good. There are still cycling references between two classes... Would someone help me to improve it? Thanks...

恐怕这个提议的模式并不好。两个班级之间仍然有自行车参考......有人可以帮助我改进吗?谢谢...

回答by Dummy00001

Would someone help me to improve it?

有人会帮助我改进它吗?

In such cases I generally resort to something like this:

在这种情况下,我通常会求助于这样的事情:

 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);
 };

And then use the numeric node_id_tinstead of Node2DCart *. One can also throw in a std::set(or std::map, updated/tested in the AddNode()) to ensure that all the Node2DCart objects are unique and if not reuse id of the existing object.

然后使用数字node_id_t而不是Node2DCart *. 还可以输入一个std::set(或std::map,在 中更新/测试AddNode())以确保所有 Node2DCart 对象都是唯一的,并且如果不重用现有对象的 id。

Essentially an addressingscheme, providing each node with a unique global identifier. Not the nicest/easiest solution, with a global container, but helped me more than once. Especially to avoid memory leaks and to ensure clean destruction of the whole hierarchy of interdependent objects.

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

Instead of typedef int node_id_tone can also use struct node_id_t { int id; };and overload conversion operators to simplify node id lookups.

typedef int node_id_t也可以使用struct node_id_t { int id; };和重载转换运算符来简化节点 id 查找,而不是一个。

回答by justik

In my opininon, the solution replacing pointers with indices in some cases will be slow.

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

  • If we do not delete any point, point_id will represent index of he point, eg. nodes[poin_id], it is ok.

  • But if we delete any point of the list, point_id will not represent its index in the list. We will have to use std::find and get point_id of the found point. This significantly reduces the speed of the code...

  • If we delete any point we can reindex list of points to avoid problems mentioned above. But we do not have to forget to reindex all meridinans start / end indices... But it takes some time and does the same as the copy constructor in the question. And I think, that affecting the data of some class by another class using copy constructor represents not very suitable proposal of the data structure...

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

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

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