But do you really need arenas? Does doing allocations in a traditional way creates a bottleneck in your specific use-case? Or you just want to justify broad manual memory management (with its bugs and secure vulnerabilities) in hope to gain (or not) a tiny amount of extra performance?
But arenas can't be used in any case. They are suitable only if large amounts of allocations take place once and need to be deallocated all at once. If reallocation of freeing of individual memory chunks is needed, arenas can't be used, so, it's needed to manage each allocation individually, for which containers is a better choice compared to manual memory management.
It's fairly straightforward to compose memory arenas with a pool allocator in these circumstances.
1) An allocated memory chunk cannot outlive its arena (leaks are impossible). You probably mean a stale reference? The arena is put at such a level in the memory hierarchy that this bug becomes impossible. The bug here would be that the allocation was done in the wrong arena. In C this would be avoided by putting temporary arenas in a local function scope by passing them as parameters. Fool proof references require C++ smart pointers. This is one example of you mixing concepts. Smart pointers/containers can still be used with arenas.
2) You mix up arenas and bump allocators. An arena can also use a pool allocator for example. Arena refers to the concept of scoping blocks of allocations.
3) Individual deallocations and arenas are not exclusive, for example using pools. But even with bump allocators free lists are a thing (and linked lists are more attractive in bump allocators because of locality).
You probably don't want to have an Arena in main, and you do all of your allocations from there, for example. That "just" leaks everything.
Here's a classic Arena-with-rewind bug:
{
Arena a;
avec<int> v(a);
{
RewindMark rm(a);
v.push(1); v.push(1); // Trigger resize
}
v[2] // Oh no! The underlying data array has been deallocated
}Generally, it's best to avoid the rewind trick, IMO, it makes it difficult to create composable programs.
As I know in newer C++ standards there is something which allows to workaround this issue. Or at least there are proposals for this.
C++ added polymorphic memory allocators in C++17 along with polymorphic versions of all standard library containers under the std::pmr namespace, so that you have std::pmr::vector, std::pmr::map, etc... all of which fully abstract out the details of memory allocation.
Also, with allocators you can replace new and delete, but you can't implement anything that doesn't fit into the new/delete paradigm, like any allocation strategy that requires moving objects.
Since C++11 it is permissible to write stateful memory allocators including arena based memory allocators. You can even write memory allocators that are tied to a specific object, so called sticky allocators.