Take a look at this innocent piece of code:
vector<vector<int>> arr{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16},
};
int n = arr.size();
for (int i = 0; i < n/2; i++) {
for (int j = 0; j < n/2; j++) {
tie(arr[i][j], arr[j][n-i-1], arr[n-i-1][n-j-1], arr[n-j-1][i]) =
{arr[j][n-i-1], arr[n-i-1][n-j-1], arr[n-j-1][i], arr[i][j]};
//tie(arr[i][j], arr[j][n-i-1], arr[n-i-1][n-j-1], arr[n-j-1][i]) =
// tuple{arr[j][n-i-1], arr[n-i-1][n-j-1], arr[n-j-1][i], arr[i][j]};
}
}
for (auto& i : arr) {
for (int j : i)
cout << j << ' ';
cout << '\n';
}
Outputs (with optimizations disabled):
4 8 12 16
3 7 11 15
8 7 10 14
4 3 9 13
which is totally gibberish.
Using tuple{}
instead of initializer list ({}
) for tie()
gives the correct answer. This behavior is observed both on GCC and clang.
In fact, this is present with code as simple as this:
int a = 1, b = 2;
tie(a, b) = {b, a};
This once again shows one of the dark sides of C++. Hope no one spends 30 mins searching for such bug after this blog :):
omg same on my laptop why
Tuple creates a copy of the value, and the initializer list will be used to create a temporary object of type
std::tuple<int&, int&, int&, int&>
, same as the left hand side, as this is the best overload. Therefore it's the same as writing out four assignments, which is pretty much guaranteed to produce incorrect results. I'm not sure whether the order of assignments is well defined.I visualized this behavior with a custom class:
Then, with the
initializer-list
optionwe will see
which obviously gives wrong results. With the
tuple
method:we see
which must be correct.
I also read at the end of this thread that tuple assignment ordering may be left up to the compiler to allow for earlier assignment of throwable types, but I failed to recreate this on any compilers I tried. Still, it may be good to assume that ordering is not guaranteed.
Here is what I tried:
But on all compilers I had access to, I could only get the result
which is inconclusive.
Hope no one spends 30 mins searching for such bug after this blog
who ever code like this!? (except pythonists)
Well, yeah you got me, I'm a pythonista undercover :)
BTW I found a prettier (=hard to understand) method:
I think this is what you're looking for