|
|
|
|
|
by cyber_kinetist
1624 days ago
|
|
Although I'm not _cart, I had a similar experience in making a (hobbyist) 2D game engine both in Rust and C++, and the problem you're facing (similar to the ABA problem) is not a memory safety error but more of a logical bug inherent in naively programmed object pools and is totally language-agnostic. When you create an object pool as Vec<Option<T>> and use a single array index as resource IDs, you risk this scenario: "X has a reference to resource A from object pool, A is destroyed and later reused by the object pool for resource B, now X has a reference to resource B". The problem is that the resource IDs will become invalidated as the object pool reuses its slots. The incremental generational counter is a way to check object lifetimes in object pools at runtime, and this is a solution to a logical error (which can be applied regardless if your language has a borrow checker or not). If you've had weird errors while using generational arrays, chances are that 1) you've exhausted your generational counter and it has overflowed 2) your generational array code is incorrect. The verdict: Rust's lifetimes does not make you safe from non-memory-safety related bugs. It still gives you some really powerful abstractions to fight these bugs (like enums, traits, Option<T> and Result<T, Err> types), but other than that you're on your own. (About circular references between components... doesn't this also get solved by generational indices? With Arc<T> types you're going to have circular dependencies that don't get freed because of reference counting, but with generational indices you're free from that issue since you're manually managing resource lifetimes anyway. And if you're having trouble figuring out how to manage these dependencies, the solution might be to refactor your code. My experience of using generational arrays was that it will naturally move your code-base towards centrally managing resources in a unified fashion, which is rather different than the usual Rust/C++ model of every object having its own independent ownership. After embracing it I tend to have less of those resource management dependency headaches.) |
|