Another option instead of using Rc/Arc is to use integer indices/handles into (e.g.) a vector holding your objects. Then you can have safety (in the sense of there being no language-level UB) by bounds checking your indices (you can do even better if you use a generational arena and attach a generation counter to your indices), and you can still have arbitrary object graphs that way.
I think that this pattern is common in C++ game programming as well (e.g. when using entity component systems), because using pointers or references everywhere and building complicated object graphs is a recipe for object lifetime issues.
I would be surprised if anyone could handle the mental complexity of managing ownership in arbitrary object graphs without there being some simplifying idea (like that of an ownership tree) involved, even if it's not enforced at the compiler level (as it is in Rust, but it isn't in C++).
That works in a static environment, but when you're constantly deleting objects, you need a hash or tree. That has more overhead.
The basic constraint inside virtual world viewers is that anything can change at any time, but usually it doesn't. The "not changing" case has to be efficient.
> using pointers or references everywhere and building complicated object graphs is a recipe for object lifetime issues.
It's also that indices are the better and cleaner "identities" compared to pointers. Pointer values include runtime baggage, and it shows if one tries to do parallel arrays or serialization.
On this, have you found any studies in different data structures to support the mapping between integers and the underlying objects? Personally, I'm working on a Hexastore that requires maintaining order of the 2 in parallel.
I think that this pattern is common in C++ game programming as well (e.g. when using entity component systems), because using pointers or references everywhere and building complicated object graphs is a recipe for object lifetime issues.
I would be surprised if anyone could handle the mental complexity of managing ownership in arbitrary object graphs without there being some simplifying idea (like that of an ownership tree) involved, even if it's not enforced at the compiler level (as it is in Rust, but it isn't in C++).