None of the allocator traits mention lifetimes. However, some allocators may be local in the sense that their own lifetime and that of the allocated memory is limited. For example, a stack allocator or an instance of bumpalo that is not in a static. How is and how should this be handled?
The type implementing
AllocRef is expected to encapsulate the lifetime if necessary -- so, implementing it for a reference to a
bumpalo memory pool is what you would do, not implement it directly on a pool instance. Does that make sense?
AllocRef because types that implement
Alloc are a reference, smart pointer, or ZSTs. This question is another reason, why this rename is a good idea.
It is not possible to have an allocator like
MyAlloc([u8; N]), that owns the memory and also implements
Alloc. That would mean, that moving a
Vec<T, MyAlloc> would need to correct the internal pointer, which is not possible. You have to encapsule the lifetime yourself by
impl AllocRef for &(mut) MyAllocator, or pass the lifetime to the allocator directly. The former is prefered IMO.
Would the same "trick" be necessary to make types using not-thread-safe allocation?
In other words, a Vec you can't Send because the allocator only lets you dealloc in the same thread that made the allocation in to start?
Or would those take even further type hackery?
I havn't tried this out, but my first guess is, that's possible.
that certainly seems like a very important case to support
eg, the windows process heap is thread safe, so slow, but you can make thread local heaps if you want to go faster
Can't you just implement
!Send for your allocator?
Something like in this playground?
Probably, I mostly wasn't sure if it'd work out like that with allocref too
I just tried it out with
impl ... for MyAlloc,
impl ... for &MyAlloc, and
impl ... for &mut MyAlloc. Everything works :)
That is a very interesting way of inheriting properties of the allocator to the allocations.
This way is only suited for very few traits, as calling those traits is ugly. We don't expect users to call allocators directly in most cases. Mostly they will be used behind a generic type, which abstracts away this.
sounds like a red flag to me
directly using the allocator shouldn't give the user a hard time.
To me as well, Box was being specified to be equivalent to allocating the layout exactly so that one can manually allocate and initialize it for example.
I have tried out this a bit more. When implementing
MyAlloc, everything works as before. When implementing it on
&MyAlloc, the methods has to be called on a reference. This means either, you need
let my_ref = &my_alloc; my_ref.alloc(...);
I'm slightly confused what it means to implement
AllocRef for a
&mut MyAllocator. How long would the returned memory need to be valid and can be assumed unique? Is it the lifetime of the
BuildAllocRef that returned this mutable reference? Or the lifetime of the mutable reference itself? That is important if I have a bump allocator with reset.
I'm asking about the mutable reference in particular since the
BuildAllocRef can not return the original reference with its full lifetime. For a
BuildAllocRef that returns
&_ this is possible by cloning some original reference which it contains.