Strange link behavior in C ++

I have a pretty 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 during commenting you get 5, 2, 3, 4 , but when you uncomment ints.push_back(y); , you get 1, 2, 3, 4, 1 . I will write again to be completely clear about the problem: you get [-->1<--], 2, 3, 4, 1 instead of 5, 2, 3, 4, 1 or even 5, 2, 3, 4, 5

This behavior turns me on ... What happens under the hood?

+4
source share
3 answers

When you click back on a vector, if the vector does not have enough memory allocated to store the new element, it allocates a new larger block of memory, moves the elements, and frees the old memory. If this happens, any references or pointers to elements of the vector are invalid.

So, after you push back when you assign 5 to y , this behavior is undefined 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.

+15
source

You need to consider the redistribution that can occur when calling std::vector::push_back .

 int &y = ints[0]; ints.push_back(y); y = 5; 

The third statement may cause undefined behavior if such a redistribution is performed. If this happens, you will lose all the guarantees you might think of. Having received this condition, in reserv 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 cppreference table shows what happens exactly and when iterators are invalid.

Usually you do not want to have free links or pointers to items stored in the container that may be invalid; if it’s really necessary, reload the address or select a container that offers more guarantees regarding redistribution, for example std::deque , std::forward_list or std::list .

+4
source

I believe you are dropping a copy. The reason is because your vector is of type int, not type & int, so it implicitly throws the link, creating a copy of the dereference.

In the example where push_back is commented out, you did not add your copy to the end of the vector and still have a link pointing to the first element, that is, you can change the element through the link. However, as soon as you press push_back, the vector will be changed, and the objects inside it will be moved, any links or pointers to these objects are invalid.

You can see this clearly by simply making your vector set large when it is built. i.e.

 vector<int> ints(5); ints = {1,2,3,4}; int &y = ints[0]; ints.push_back(y); y = 5; for (auto &x : ints) { cout << x << ", "; } // output = 5,2,3,4,1 
+1
source

All Articles