I have the following code:
#include <vector>
#include <iostream>
std::vector <int> a;
int append(){
a.emplace_back(0);
return 10;
}
int main(){
a = {0};
a[0] = append();
std::cout << a[0] << '\n';
return 0;
}
The function append()
as a side effect increases the vector size by one. Because of how vectors work, this can trigger a reallocation of its memory when exceeding its capacity.
So, when doing a[0] = append()
, if a reallocation happens, then a[0]
is invalidated and points to the old memory of the vector. Because of this you can expect the vector to end up being {0, 0}
instead of {10, 0}
, because it is assigning to the old a[0]
instead of the new one.
The weird thing that confuses me is that this behavior changes between C++14 and C++17.
On C++14, the program will print 0. On C++17, it will print 10, meaning a[0]
actually got 10 assigned to it. So, I have the following questions whose answers I couldn't find:
a[0]
's memory address after evaluating the RHS of the assignment expression? Does C++14 evaluate this before and that's why it changes?This code is UB prior to C++17, as pointed out in comments, due to C++ evaluation order rules. The basic problem: Order of operations is not order of evaluation. Even something like x++ + x++
is UB.
In C++17, sequencing rules for assignments were changed:
- In every simple assignment expression E1=E2 and every compound assignment expression E1@=E2, every value computation and side-effect of E2 is sequenced before every value computation and side effect of E1