I have fairly short question:
vector<int> ints{1,2,3,4};
int &y = ints[0];
// ints.push_back(y);
y = 5;
for (auto &x : ints) {
cout << x << ", ";
}
Why while commented you get 5, 2, 3, 4
but when you uncomment ints.push_back(y);
you get 1, 2, 3, 4, 1
. I'll write it once more in order to be perfectly clear about the problem: you are getting [-->1<--], 2, 3, 4, 1
, instead of 5, 2, 3, 4, 1
or even 5, 2, 3, 4, 5
This behaviour drives me nuts... What happens under the hood?
When you push back onto a vector, if the vector doesn't have enough memory allocated to store the new element, it allocates a new larger memory block, moves the elements over, and frees the old memory. If this happens, any references or pointers to elements of the vector are invalidated.
So, after the push back, when you then assign 5
to y
, it is undefined behavior, because y
is an invalid reference, and there is no reason to expect the assignment to have any effect on any elements of the vector.
You need to consider the reallocation that might happen when std::vector::push_back
is called.
int &y = ints[0];
ints.push_back(y);
y = 5;
The third instructions may cause undefined behavior if such reallocation is performed. If that happens, you lose all the guarantees you could think of.
Taking out this condition, by reserv
ing memory, the expected result is shown
5, 2, 3, 4, 1,
std::vector<int> ints{1,2,3,4};
ints.reserve(128); // Note
int &y = ints[0];
ints.push_back(y);
y = 5;
The table at cppreference shows what happens precisely and when iterators are invalidated.
Usually, you don't want to have free references or pointers to elements stored in a container that could be invalidated; if that's truly needed, reload the address or choose a container that offers more guarantees about reallocation such as std::deque
, std::forward_list
or std::list
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With