Search code examples
c++pointersheap-memorystack-memory

What happens when I access a pointer when it's stored in a vector which is on the stack?


std::vector<object*> objects;
Object* o = new Object();

objects.push_back(o);

I want to access objects[0]. So, when I access it, is there a pointer to the stack, then the heap? Or, how does this work?


Solution

  • There's a few things to unpack here.

    First off, let's say you have a vector<object*> as you state, and that it is declared with automatic storage duration.

    void f()
    {
        // declared with automatic storage duration "on the stack"
        std::vector<object*> my_objects;
    }
    

    A vector by it's nature stores a contiguous block of memory, which is essentially an array of n objects of which it can store, in our example the vector can contain 0..n object*, and the implementation will do that by having a pointer to the first element, and that contiguous block of memory is stored "on the heap".

    void f()
    {
        // declared with automatic storage duration "on the stack"
        std::vector<object*> my_objects;
    
        // now, my_objects holds 10 object*, and the storage for them
        // is allocated "on the heap"
        my_objects.resize(10);
    }
    

    It gets interesting because when we're storing object* we can't know if it was allocated on the heap or not. Take the following example:

    void f()
    {
        // declared with automatic storage duration "on the stack"
        std::vector<object*> my_objects;
    
        // now, my_objects holds 2 object*, and the storage for them
        // is allocated "on the heap"
        my_objects.resize(2);
    
        auto dyn_obj = std::make_unique<object>();
        object auto_obj;
    
        my_objects[0] = dyn_obj.get();
        my_objects[1] = &auto_obj;
    }
    

    Above, we have a situation where the storage for my_objects.data() is allocated on the heap, the object pointed to by my_objects[0] is allocated on the heap, while the object pointed to by my_objects[1] is not.

    As in your example:

    std::vector<object*> my_objects; // automatic storage duration
    object* o = new object;          // o has automatic storage duration
                                     // while what it points to is "on the heap"
    
     my_objects.push_back(o);        // an allocation will happen
                                     // because my_objects has to
                                     // allocate storage to hold o
    

    my_objects is "on the stack", as is o. When the scope containing these things is exited, they will be "destroyed". my_objects will run it's destructor, while o will "just go away".

    The call to my_objects.push_back() will allocate memory "on the heap" to hold 1 * sizeof(object*) ( at least ), and will copy the value of o into that storage space.