SYSTEMS LEARNING LAB / PERSONAL PROJECT

C++ Mastery.

Learning the machinery by rebuilding the abstractions.

C++MemoryTemplatesSanitizers

C++ Mastery is a hands-on learning repository, not a production standard-library replacement. I use small C and C++ experiments to make lifetime, allocation, generic programming and failure behavior concrete as I move deeper into platform engineering.

Learning by rebuilding

Using a container is different from implementing its lifetime rules. The lab takes familiar concepts apart: when storage becomes an object, what a move actually transfers, what happens during reallocation and what must remain true when construction throws.

Object lifetime and ownership

The Tracer experiment logs construction, copying, moving, assignment and destruction. Its nested-scope example is deliberately small enough to follow by hand.

    Tracer a{1};

    {
        Tracer b{2};
    }

    std::cout << "leaving function\n";
Tracer a is constructed in the function scope. Tracer b is constructed and destroyed inside the nested scope; a is destroyed when the function exits.

The same source explores copy/move operations and forced std::vector reallocation. Lifetime experiment →

Vector as the centerpiece

An example Vector grows from four live objects in capacity four to five live objects in capacity eight. The appended object is constructed before existing objects are relocated; unused capacity remains raw storage.
The diagram illustrates the repository’s growth experiment. Allocated capacity and live object count are different quantities.
  1. Allocate raw storage Allocator + capacity
  2. Construct appended value Before aliased source can move
  3. Relocate existing objects std::move_if_noexcept
  4. Destroy old objects End their lifetimes
  5. Deallocate old storage Commit the new allocation

Constructing the appended element first matters for v.push_back(v[0]): the argument refers into the vector’s current allocation. Relocating it too early can change or invalidate the very value being appended.

            for (; relocated < size_; ++relocated) {
                std::construct_at(
                    new_elements + relocated,
                    std::move_if_noexcept(
                        data_[relocated]
                    )
                );
            }

The implementation separates allocation, construction, destruction and deallocation rather than treating them as one operation. Vector implementation →

Exception safety

Make failure happen on purpose

ThrowOnCopy counts live objects and throws after a chosen number of copies. The tests check that partially constructed copies are cleaned up.

Preserve the destination

Copy assignment builds a temporary before swapping. If the copy fails, the original destination remains intact; the test inspects its values and live-object count.

Clean up partial growth

The growth path tracks relocated objects and whether the appended object exists, then destroys completed constructions and releases the new allocation on failure.

Keep guarantees precise

move_if_noexcept prefers copying when a throwing move could weaken rollback. A throwing move-only type or self-move has different guarantees; the lab avoids assuming a universal unchanged-state promise.

Failure, self-copy and self-move experiments →

Alignment and layout

struct alignas(64) CacheLineData {
    int values[16]{};
};
Three 64-byte-aligned CacheLineData objects with sixteen int slots each. The experiment inspects addresses and stride, without claiming a measured performance gain.

Printing addresses, offsets and address modulus makes alignment observable. It is a way to reason about layout and locality; this case study makes no cache-speedup or benchmark claim.

Modern C++ concepts

Concepts

Express the operations a template requires and observe how constraints shape overload selection.

Source ↗

Template deduction

Follow which types are deduced and which conversions happen after deduction.

Source ↗

Value categories and forwarding

Trace lvalues, rvalues, references and forwarding through function boundaries.

Source ↗

Fold expressions

Reduce a parameter pack while making evaluation and operation choice explicit.

Source ↗

Type deduction

Compare auto, decltype and reference behavior through runnable examples.

Source ↗

RAII

Give resource ownership a lifetime boundary through an IntBuffer implementation.

Source ↗

C before C++

The C vvector lab makes the lower layer explicit: raw storage, element size, allocation and the bookkeeping a generic container needs. It is a useful comparison with the typed object-lifetime rules in C++.

C labC++ lab
Explicit byte storage and element sizesTyped allocator-backed storage
Manual resource protocolConstruction, destruction and RAII
Caller-visible generic storage rulesTemplates, forwarding and exception paths

C vvector source →

Tooling

The workspace uses CMake with C17 / C++26 settings and explicit warning flags. AddressSanitizer and UndefinedBehaviorSanitizer are enabled for selected targets, including the C vector and RAII labs; sanitizer coverage is not claimed for every target.

Small executables make it easy to isolate a question, inspect output, force a failure and return to the implementation. Build configuration →

Direction of travel

This work supports a longer move into AOSP, AAOS platform internals and native boundaries. It does not stand in for production platform experience. The aim is to build the understanding needed to reason about ownership, memory and failure when Android application code reaches into lower layers.