Also, you have opened my eyes in what would be the heap is done in Ada. I couldn’t figure out that you may just use an unbounded array in order to implement dynamic memory. Now a lot of stuff makes sense. I am curious about how the implementation by the compiler works under the hood, since it must do some equivalent to dynamic memory management with some guarantees offered by the nested nature of declarations.
The pool segments are managed by an unbounded array of access types. The unbounded array manages the access types of its elements. If you replace a non-null element the old value (an access) is freed. When finalized the array frees all its non-null elements. So no explicit deallocation is visible.
P.S. Simple components predates the standard library containers. Now you can create an unbounded array of managed access types using the standard library. That would be a vector Ada.Containers.Vectors of holders Ada.Containers.Indefinite_Holders. It would be probably less performant (holder type vs direct access type) but logically same.
Ok, I see now. Thanks! ![]()
Sorry, not obvious to a noob like me.
Why? Don’t those take care of the whole deallocation behind the scenes?
Edit: Never mind, I got it myself. Mixing pool allocation and controlled types is dangerous.
It is not just controlled objects and controlled components/elements. Anything that requires some finalization.
P.S. One can fix that by maintaining a list of allocated objects in the pool and when the pool mark is swept under an object in the list finalize it. But this defeats the very idea of having arena.
P.P.S. There is a language rule about finalization of access types. When the type goes out of scope, all objects allocated for the type get finalized. This is same as above. Ada run-time maintains a list of all allocated objects for the access type. If you have a leak, you may get unexpected finalization error messages escalating to Program_Error because the run-time tries to finalize strayed objects way too late.
That’s correct
But memory is reclaimed only when attribute Storage_Size is specified. (See #8 above.)
Note: Finalization and deallocation are not the same.
A finalized object does no longer exist. Storage reclamation is not implied.