2

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?

user1157885
  • 1,999
  • 3
  • 23
  • 38

3 Answers3

3

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>.

Christophe
  • 68,716
  • 7
  • 72
  • 138
  • but vector do reserve some additional memory, and just adding one more element won't make it to reallocate whole vector. – Sanmveg saini May 16 '20 at 16:26
  • @Sanmvegsaini In certain cases (just when the `size() == capacity()`) _just adding one more element_ reallocates in fact _whole vector_. – Scheff's Cat May 16 '20 at 16:28
  • @Sanmvegsaini exact! I highlighted **might** just to make clear that it does not happen always but that it can. – Christophe May 16 '20 at 16:28
  • @Sanmvegsaini unless you *checked* the vectors `size()` and `capacity()` before adding elements, you have no idea when it will resize. – Jesper Juhl May 16 '20 at 16:29
  • 2
    @George Please provide proof of that claim. I believe you are wrong. – Jesper Juhl May 16 '20 at 16:31
3

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].

sanitizedUser
  • 1,723
  • 3
  • 18
  • 33
1

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.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335