Referencing a specific index in a vector

Viewed 102

I'm trying to reference a certain index within a vector but whenever I add new items to the vector the pointer isn't pointing towards the original value.

The example I have is this:

std::vector<int> a;
a.push_back(1);
int* a_1 = &a[0];
a.push_back(2);

When I do:

int* a_1 = &a[0];

It's referencing the first value which is 1, but once I push a new item onto the vector the value becomes undefined. Why is my pointer becoming undefined once I push more items onto the vector?

3 Answers

The vector is guaranteed to have contiguous items. It is also guaranteed to grow when you add new items or increase its size. This means that adding new items might require to move the vector and invalidate all the pointers to its elements.

It's explained here. More specifically, pointers and iterators can be invalidated by these vector operations. This great SO question provides an overview on iterator invalidation on all standard containers.

If you need to keep a pointer or a reference to an element, you can have a look at this SO question or switch to a container that has different invalidation rules, such as for example a map<int, int>.

Vector changes the place in memory where items are stored when number of items exceeds current capacity.

If you add new item past the capacity, all items are copied to new place. So you are referencing an old place where the item no longer sits.

To constantly reference same index, store the index. In this example store number 0. You can then retrieve the item by calling a[0].

Adding a new element to a vector can result in reallocating the memory where existent elements were stored. So references and pointers to these elements become invalid.

To avoid such a situation you can preliminary reserve enough memory using the member function reserve.

For example

std::vector<int> a;
a.reserve( 2 );

a.push_back(1);
int* a_1 = &a[0];
a.push_back(2);

std::cout << *a_1 << '\n';

Here is a demonstrative program.

#include <iostream>
#include <functional>
#include <vector>

int main() 
{
    const size_t N = 10;
    std::vector<int> v;
    v.reserve( N );

    std::vector<std::reference_wrapper<int>> rv;

    int value = 1;
    for ( size_t i = 0; i < N; i++ )
    {
        v.push_back( value++ );
        rv.push_back( std::ref( v.back() ) );
    }


    for ( const auto &r : rv )
    {
        std::cout << r << ' ';
    }
    std::cout << '\n';

    return 0;
}

The program output is

1 2 3 4 5 6 7 8 9 10 

That is all pointers to elements of the vector v stored in elements of the vector rv are valid.

Related