在不使用静态成员的情况下跨对象树共享数据的策略

时间:2014-06-15 14:05:40

标签: c++ c design-patterns tree shared-data

我处于需要在多态对象树的多个实例之间共享数据的情况,但是我再次需要共享数据" per-tree"所以在基类中使用静态类成员实际上并不是一种选择。

我不想过度负担"每个实例都有指向共享数据的额外成员指针,因此我当前的方法(考虑到我使用树)是将共享数据作为树根节点的成员,并且每次访问共享数据都要经过一系列间接,具体取决于特定节点的深度"树全局"访问数据。

由于有些情况下共享数据非常频繁(每秒数百万......至少是那些预期的内容),我想知道是否有一些设计模式可以帮助我避免间接到到达根节点,同时仍然没有将额外的膨胀引入对象的足迹。

虽然可以"缓存"根节点指针作为本地,例如用于访问共享数据的紧密循环,在许多情况下,功能将沿树节点级联,甚至在过程中切换树,因此缓存根节点指针仅适用于狭窄的上下文。

  • 请注意,静态成员的提及不会将实现的范围限制为C ++,我也添加了C标记,因为此时我对任何想法持开放态度。

2 个答案:

答案 0 :(得分:0)

与树节点交互的所有方法都将第一个参数作为指向根的指针。

flyweight包装器类可以隐藏此实现细节,您可以通过opaque类访问树节点,其中包含一个真实的树节点指针以及一个用于根目录的poimter。如果你要求孩子,它会返回另一个轻量级。

现在你的树缺少额外的指针,但接口类有额外的指针。

如果您的树节点是不可变的(逻辑上),您甚至可以复制它们的状态以减少间接成本。

template<class Data>
struct internal_tree {
  Data d;
  std::unique_ptr<internal_tree> left;
  std::unique_ptr<internal_tree> right;
};

template<class Data>
struct flyweight_tree {
private:
  internal_tree* internal = nullptr;
  internal_tree* root = internal;
  flyweight_tree(internal_tree* t, internal_tree* r):internal(t),root(r) {}
public:
  flyweight_tree() {}
  flyweight_tree(internal_tree* r):internal(r) {}
  flyweight_tree left() const { return { internal->left.get(), root }; }
  flyweight_tree right() const { return { internal->right.get(), root }; }
};

现在我们的实际internal_tree数据结构不存储指向root的指针。使用它的代码通过flyweight_tree访问它,它存储指向root的指针,但指针到root只存储在访问点,永远不会长期存储。

如果你想要一个parent,你甚至可以将它实现为一个轻量级,其中flyweight_tree存储std::vector指针到父级(而不是root )。这会在树节点中保存另一堆内存(没有指向父节点的指针,但是使用它的每个人都可以获得父节点,因为它们通过flyweight_tree使用它。)

我们可以在internal_tree中实现大部分工作,它将flyweight_tree存储的信息作为参数,或者我们可以在flyweight_tree中实现大多数树逻辑,将internal_tree留作紧凑的“长期存储”结构。

答案 1 :(得分:0)

我能想到的可能性是:

  • 如果您的根数量有限,则将偏移量(例如在uint8_t中)存储到具有根的静态数组中。例如,如果您只有5-10个根,则不需要为每个节点存储高达64位的数据。
  • 为什么不运行每棵树&#34;在自己的过程中(在操作系统级别)?这样,每个根都可以存储为静态数据并全局访问。
  • 如果你可以绑定节点数,也许你可以使用一个特殊的分配器:首先在给定内存边界的开头分配你的根,例如0x0010000,0x0020000等...然后检索地址root用每个节点的简单减法/位移?但是你必须能够确保你可以在每棵树的内存区域内分配所有节点。