4 ms·
There's the third option, which is what Rust and C++ do by default, where types have destructors that are run when the value goes out of scope, but also have me
by connicpu 4y ago
There's the third option, which is what Rust and C++ do by default, where types have destructors that are run when the value goes out of scope, but also have mechanisms to be activated manually at a precise moment if you know what you're doing and have specific needs.
- haberman 4y agoRAII is not a silver bullet. RAII wants to have neat recursive ownership and cleanup of everything, which is undoubtedly a nice model, but sometimes in low-level code you have to choose between nice recursive ownership and performance. For example, Protocol Buffers are trees of objects. Originally they were simple and had recursively-owned, heap-allocated nodes. But it turns out that traversing and deleting a big graph of heap-allocated objects is expensive, and arenas are more efficient. But arenas make you give up recursive ownership.
- connicpu 4y agoWhich is why low level languages like C++ and Rust make RAII the default in their standard library (easy, simple), but it's still completely possible to manage the memory on your own if that's necessary for the task at hand. Having easy defaults with the capacity to do everything by hand if you need to is the most flexible system.
- mcguire 4y agoThe last time I looked (which has been a while, I admit), that meant that you had a very hard time using any of the standard library types with an arena or whatever form of management you used for your specialized code. What does that look like now?
- tialaramex 4y agoIf you're willing to write Nightly Rust, you can use the allocator_api feature to have the types which allocate take an allocator parameter so e.g. Vec::with_capacity_in(10, arena_allocator) ... obviously user-defined types don't know these allocators exist and so may not provide a way to pick which allocator is used, whereas in Zig this is "always" how it worked. For stable Rust, until/ unless allocator_api is stabilized, you will need to replace the global allocator for your code with one that has the desired behaviour. That applies to everything using an allocator, but on the other hand you lose considerable flexibility.
- gpderetta 4y agoThere is no incompatibility between RAII and arenas. RAII doesn't require heap allocation.
- kristoff_it 4y agoThat's not really the point. If you're using an arena it means that you plan to reset it at some point and erase in bulk everything that was stored on it all at once. This is the opposite of letting the destructor of every object run.
- connicpu 4y agoNot every object in an RAII language needs a destructor, e.g. objects that don't manage their own memory because they came from an arena
- nextaccountic 4y agoIn Rust terms, the arena should own the data and each object should just borrow from the arena. In Rust, when you drop a borrow it doesn't deallocate the memory; only owned values deallocate on drop (that is, in the destructor). Besides, borrowing enforces that the arena won't drop while the borrows are still outstanding. https://manishearth.github.io/blog/2021/03/15/arenas-in-rust/ https://manishearth.github.io/blog/2021/03/15/arenas-in-rust...
- kaba0 4y agoThis is by definition manual memory management.
- connicpu 4y agoI would argue RAII is still a type of automatic memory management, but it has the determinism and ability to reason about what's going on the same way fully manual management does.
- kaba0 4y agoFrom the Garbage Collector handbook I got a very great quote about what automatic memory management really is. I will butcher it up, but the basic essence is that automatic memory management is above all a software design tool — well designed programs are built from components that are highly cohesive but loosely coupled. What it means for memory management is that a component shouldn’t have to care about how other modules handle memory for correct working. This is possible with a GC, but isn’t with manual memory management, and RAII doesn’t change it — function signatures leak memory management concerns in both Rust and C++. Ongoing refactoring and maintenance costs are also higher in low-level languages due to this reason.