Beginner's Guide
    First Steps
    Input & Output
    Custom Types – Part 1
    Diagnostics
    Standard Library – Part 1
    Function Objects
    Standard Library – Part 2
    Code Organization
    Custom Types – Part 2
    Generic Programming
    Memory Management
    Software Design Basics

    Memory (Basics) Memory (Basics) Memory

    Memory Model Model

    On Paper: C++'s Abstract Memory Model On Paper: Abstract Memory Model On Paper

    Concrete implementations (= compiler, C++ runtime, …) can employ different strategies to satisfy these specifications on a concrete platform (= CPU architecture, operating system, …).

    memory is divided into bytes

    an object as a piece of memory at an address

    Example: std::int16_t i = 1234; is an object with name i, a size of 2 bytes (= 16 bits) and value 0000010011010010 which according to its type int16_t represents the number 1234.


    Note that the abstract model doesn't say anything about how memory is partitioned or about cache hierarchies.

    Automatic object lifetime tied to start & end of { } block scopes local variables, function parameters
    Dynamic object lifetime controlled with special instructions objects that can be created/destroyed on demand and independent of block scopes
    Thread object lifetime tied to start & end of a thread per-thread storage
    Static object lifetime tied to start & end of the program singletons, …

    In Practice: Actual Memory Handling In Practice: Memory Handling In Practice

    • are constrained by features & limitations of the target platform (CPU/memory architecture, operating system, compiler)
    • need to fix choices left open by the C++ standard, e.g., number of bits in a byte (8 on most platforms)
    • need to support object storage duration/lifetime schemes described by the C++ standard (automatic, dynamic, thread, static)

    Automatic Storage Automatic Storage Automatic

    A stack is generally used for objects of automatic storage duration such as local variables (including function parameters):

    Use the navigation buttons on the right/left to go forward/backwards.

    Dynamic Storage: std::vector Dynamic Storage std::vector

    For now: only by using std::vector

    Next: more standard library containers (set, map, …)

    Much later: manual dynamic memory allocation

    In modern C++, manual allocation is actually only really necessary if you want to implement your own dynamic data structures / containers.

    std::vector Memory Layout Layout

    Each vector object holds a separate buffer that is dynamically allocated (on the heap) where the actual content is stored.

    Right now we only know how to allocate objects on the stack, but the vector object v itself could also be allocated on the heap (more on that in later chapters).

    vector<int> v {0,1,2,3,4};

    vector of ints memory layout

    std::vector Growth Scheme Growth

    Memory blocks, once allocated, can't be resized! (no guarantee that there is space left directly behind previously allocated memory block)

    Dynamic array implementations separate the array object from the actual memory block for storing values.

    Growth is then done the following way:

    • dynamically allocate new, (≈1.1-2×) larger memory block
    • copy/move old values to new block
    • destroy old, smaller block

    std::vector Size vs. Capacity Size/Capacity

    • .size() number of elements in vector
    • .resize(new_number_of_elements)

    • .capacity() number of avail.available memory slots
    • .reserve(new_capacity)
    
    vector<int> v;
    v.push_back(7);
    v.reserve(4);
    v.push_back(8);
    v.push_back(9);
    
    auto s = v.size(); auto c = v.capacity();
    v.resize(6,0);
            capacity size
                   0    0
    
    • 7
    • 1 1
    • 7
    • 4 1
    • 7
    • 8
    • 4 2
    • 7
    • 8
    • 9
    • 4 3

    s: 3 c: 4
    • 7
    • 8
    • 9
    • 0
    • 0
    • 0
    • 6 6

    If you know the (approximate) number of elements in advance ⇒ reserve before adding elements to the vector!

    This avoids unnecessary memory allocations and copying during the growth phase.

    Use the navigation buttons on the right/left to go forward/backwards.