Class StackAllocator

Class Documentation

class StackAllocator

Bump/linear allocator providing O(1) allocation via pointer increment.

StackAllocator maintains a contiguous buffer and a ‘top’ marker. Allocation simply increments the top pointer (bounds-checked), making it extremely fast compared to general-purpose allocators. This is ideal for temporary allocations with similar lifetimes, such as per-frame data in game engines.

The key feature is marker-based bulk deallocation: capture a marker with get_marker(), perform any number of allocations, then free_to_marker() to instantly free everything allocated since that marker by resetting the top pointer.

Individual free() is supported but only efficient for LIFO (stack) order. The allocator tracks allocations in an internal map, so marker-based freeing is preferred for performance.

Thread Safety: NOT thread-safe. Designed for single-threaded contexts where one thread owns the allocator for its temporary allocations.

Example - Per-frame temporary allocations:

StackAllocator frame_alloc(1024 * 1024);  // 1MB buffer

void process_frame() {
    auto marker = frame_alloc.get_marker();

    // Allocate temporary data for this frame
    auto* entities = frame_alloc.alloc<EntityList>(100);
    auto* transform_buffer = frame_alloc.alloc<Transform>(entities->size());

    // ... use data throughout frame processing ...

    // Free all frame allocations instantly
    frame_alloc.free_to_marker(marker);
}

Important Notes:

  • Markers become invalid after resize() or clear()

  • Default size is 1KB (see implementation) - size appropriately for your use case

  • Allocation throws std::bad_alloc when buffer is full

  • Alignment: No alignment guarantees beyond byte alignment. Types requiring stricter alignment (SSE vectors, cache-line alignment) may exhibit undefined behavior. For aligned types, use aligned_alloc or posix_memalign instead.

  • Complements mimalloc (the global allocator) for specific high-performance patterns

See also

PoolAllocator for fixed-size object pools with arbitrary free/reuse patterns

See also

BufferedAllocator for multi-frame buffering with round-robin StackAllocators

Public Types

using marker = size_t

Type alias for position markers used by get_marker() and free_to_marker(). Represents a position in the stack’s buffer (offset in bytes from buffer start).

Public Functions

StackAllocator()

Constructs the stack allocator with default size

explicit StackAllocator(size_t total_size)

Constructs the stack allocator with the specified total size.

Parameters:

total_size – Total size of the stack allocator in bytes.

void *alloc(size_t size)

Allocates a given size from the top of the stack

Parameters:

size – The size to allocate

Returns:

A pointer to the beginning of the allocated memory

template<typename T, typename ...Args>
inline T *alloc(Args&&... args)

Allocates memory and constructs an object of type T

Template Parameters:
  • T – The type of object to allocate

  • Args – Constructor argument types

Parameters:

args – Constructor arguments

Returns:

Pointer to the new object

template<typename T>
inline void free(T *p)

Destroys and frees an object of type T

Template Parameters:

T – The type of object to free

Parameters:

p – Pointer to the object

void free(void *p)

Frees an allocation made by this stack allocator.

Parameters:

p – The pointer to the memory to free. This must be a pointer allocated by this stack allocator.

marker get_marker() const
Returns:

A marker to the current top of the stack.

size_t get_size() const

Gets the total size of the stack allocator.

Returns:

The size of the stack in bytes.

void free_to_marker(marker m)

Frees all allocations made after the specified marker.

This instantly resets the ‘top’ pointer to the marker position, freeing all memory allocated since get_marker() was called. This is the preferred deallocation method for bulk freeing as it has zero iteration cost.

WARNING: This does not update the internal allocations map. Do not call free() on individual allocations made after this marker - the behavior is undefined. Use marker-based deallocation exclusively for bulk freeing, or use clear() to reset both the top pointer and allocations map.

Parameters:

m – The marker obtained from get_marker(). Must be a valid marker from this allocator instance. Markers are invalidated by resize() or clear() operations.

void clear()

Clears the entire stack

void resize(size_t new_size)

Resizes the stack allocator to a new size. This will clear the current allocations and reset the stack.

Parameters:

new_size – The new size of the stack in bytes.