So, for example, with Vec<T>, a method like vec.push(value) just has to return Option<T> with #[must_use] where Some(T) means that memory allocation failed, and it hands you back ownership of the element you passed into it. It works well and composes well. It's not that bad.
Conversation
Unwinding on allocation failure is a decision not to handle it. The same thing applies to most errors. It isn't actually considered during development and those code paths aren't visible in the code or tested in practice. You need the ability to inject allocation failures too.
1
I don't think most code, even low-level code, actually wants to handle it in much depth, other than running a generic handler to drop cached memory, try again, and then exit cleanly. When you do want to handle it, hidden unwinding on allocation failure really isn't good enough.
2
1
"running a generic handler to drop cached memory, try again, and then exit cleanly" is something that Rust's now-defunct condition system, and not much else, would have handled perfectly
1
en.cppreference.com/w/cpp/memory/n is a decent approach. An implementation as an example: github.com/GrapheneOS/har. It doesn't work well in C++ because it's only for new and people don't use it whenever they call malloc, mmap, etc. but it's an approach that can work well for the common case.
2
that's the obvious way to do it without direct language support, but it doesn't seem like it would compose well--would you call that in a library?
1
No, but it could have been designed to work like atexit, instead of a single handler like this. This specific API is flawed, but the idea behind it and the general approach is a good way to handle the needs of most applications. It's weird there isn't a widely adopted approach.
1
So, for example, modern malloc implementations can usually drop cached pages via MADV_DONTNEED in a memory exhaustion situation. In normal usage, they would generally use MADV_FREE. The same thing applies to many other allocators and caches. Android & Windows have APIs for this.
1
1
On Windows, you can mark a range of memory with MEM_RESET that you aren't currently using and it can be freed if there's memory pressure. You call MEM_RESET_UNDO when you want to use it again, and it tells you if your memory was released. Android has pin/unpin for ashmem.
1
1
Chromium, Firefox, etc. use this and it's just stubbed out for non-Android Linux since there's nothing to use. MADV_FREE is much nicer for a performance-oriented malloc though, because when you wouldn't want to lock in the remaining faulted pages when you hand out allocations.
1
1
So, you do need some kind of system for handling allocation failure by initially asking allocators to purge their caches, even with an API like that, but for many other volatile caches it makes sense to use that approach, like a browser's in-memory cache and they do use it a bit.
I find it weird that it isn't the norm for allocators to at least attempt this internally, for their internal caches, especially since this only impacts the cold path for handling allocation failure and shouldn't add a single branch or instruction to main code paths / sections.
1
1
It's also so typical of C++ to define that for new, while ignoring malloc, even though having it as a malloc feature would be strictly superior in the real world where new is implemented via malloc and many libraries, applications, etc. are still being used calling malloc...

