Theme Catppuccin
Make yourself at homeCatppuccin

A softer light for long learning sessions.

Appearance

Loading your preference…

Dark palette

Choose a dark palette to try it.

Light uses Latte. Your choices stay in this browser.

Back to your source shelf

Inside the companion

First Light

Make your first CPU image, rasterize triangles, and trace an allocation budget.

Project files 15

Give scratch memory a boundary

A bounded arena, allocation accounting, controlled failure, and an independent result owner.

52 lines memory_lab.cpp
#include "prism/memory_lab.hpp"
#include <algorithm>
#include <array>
#include <limits>
#include <new>
#include <vector>

namespace prism {
void* CountingResource::do_allocate(std::size_t bytes, std::size_t alignment) {
    if (bytes > std::numeric_limits<std::size_t>::max() - live_ ||
        allocations_ == std::numeric_limits<std::size_t>::max()) throw std::bad_alloc{};
    // Commit accounting after upstream succeeds; an injected failure changes
    // neither live bytes nor successful-allocation count.
    void* pointer = upstream_.allocate(bytes, alignment);
    ++allocations_;
    live_ += bytes;
    peak_ = std::max(peak_, live_);
    return pointer;
}
void CountingResource::do_deallocate(void* pointer, std::size_t bytes, std::size_t alignment) {
    upstream_.deallocate(pointer, bytes, alignment);
    live_ -= bytes; // memory_resource requires the original size/alignment.
}

MemoryReport run_memory_lab() {
    alignas(std::max_align_t) std::array<std::byte, 512> storage{};
    // Null upstream is a hard allocation boundary: no fallback to the heap.
    std::pmr::monotonic_buffer_resource arena{storage.data(), storage.size(), std::pmr::null_memory_resource()};
    CountingResource counted{arena};
    MemoryReport report;
    {
        std::pmr::vector<int> samples{&counted}; // Borrowing container dies first.
        samples.reserve(16);
        for (int value = 0; value < 16; ++value) samples.push_back(value);
        std::pmr::string temporary{"A title promoted beyond the arena lifetime", &counted};
        report.promoted_title.assign(temporary.data(), temporary.size());
        const auto before = counted.live_bytes();
        try {
            samples.reserve(4096); // Deliberately exceeds the fixed storage.
        } catch (const std::bad_alloc&) {
            report.bounded_failure = samples.size() == 16 && samples[15] == 15 && counted.live_bytes() == before;
        }
    } // Both PMR containers release their logical allocations here.
    report.allocations = counted.allocations();
    report.peak_bytes = counted.peak_bytes();
    report.live_after_scope = counted.live_bytes();
    arena.release(); // Safe only after all arena-backed containers have died.
    // report.promoted_title owns separate storage; no stale arena view is read.
    return report;
}
} // namespace prism

This is the file included with the course. Copy and download give you its complete source.

Taking your work offline? Download all course companions