I am in a situation where I need to share data across many instances of a polymorphic object tree, but then again, I need the shared data to be "per-tree" so using static class members in the base class is no really an option.
I don't want to "overburden" each instance with extra member pointers to the shared data, so my current approach (considering I use trees) is to have the shared data as members of the tree root node, and each access to shared data goes through a chain of indirections depending on the depth of the particular node through which "tree global" data is accessed.
Since there are scenarios where shared data will be very frequently (millions per second... at least that's what is intended) accessed, I wonder if there is some design pattern that can help me avoid the indirections to reach to the root node while still not introducing extra bloat to the footprint of objects.
While it is possible to "cache" the root node pointer as a local for say a tight loop that accesses shared data, there are many scenarios where functionality will cascade along tree nodes and even switch trees in the process, so caching the root node pointer is applicable only in a narrow context.
- note the mention of static members does not limit the scope of the implementation to C++, I added the C tag as well because at this point I am open to any ideas.
All methods to interact with a tree node take as their first parameter a pointer-to-root.
A flyweight wrapper class can hide this implementation detail, where you access the tree nodes through an opaque class with a real tree node pointer plus a poimter to root in it. If you ask for a child, it returns another flyweight.
Now your tree lacks the extra pointer, but the interface class has the extra pointer.
If your tree nodes are immutable (logically) you can even copy their state to reduce indirection costs.
now our actual
internal_tree
data structure does not store a pointer-to-root. Code that uses it accesses it through aflyweight_tree
, which stores the pointer-to-root, but that pointer-to-root is only stored at the point of access, never long-term stored.If you want a
parent
, you could even implement it as a flyweight, where theflyweight_tree
stores astd::vector
of pointers-to-parent (instead ofroot
). This saves another pile of memory in your tree nodes (no pointer-to-parent, yet everyone using it can get parent, because they use it through theflyweight_tree
).We could either implement most of the work in the
internal_tree
, where it takes as arguments the information thatflyweight_tree
stores, or we could implement most of the tree logic inflyweight_tree
and leaveinternal_tree
as a compact "long-term storage" structure.