While trying to ensure ascending order of two variables, I've encountered strange anomaly in Visual Studio 2012 C++ compiler that can be illustrated by the following code snippet
double x1 = 2;
double x2 = 1;
std::tie(x1, x2) = std::minmax(x1, x2);
std::cout << "x1 = " << x1 << ", x2 = " << x2 << "\n";
one would expect that x1 is 1 and x2 is 2. But they are not. Instead
//output:
//x1 = 1, x2 = 1
Is there any good explanation, just to be sure not to fall into similar trap again?
When taken by mouth: Vitamin C is likely safe for most people. In some people, vitamin C might cause side effects such as stomach cramps, nausea, heartburn, and headache. The chance of getting these side effects increases with higher doses.
There are different kinds of the operators, such as arithmetic, relational, bitwise, assignment, etc., in the C programming language. The assignment operator is used to assign the value, variable and function to another variable.
Definition of persistent side effect: "A side effect is said to be persistent at a particular point in execution if it might have an effect on the execution state at that point." [Reference: Misra C, Appendix J] c. volatile. misra.
A side effect is when a function relies on, or modifies, something outside its parameters to do something. For example, a function which reads or writes from a variable outside its own arguments, a database, a file, or the console can be described as having side effects.
std::minmax
returns its arguments back by reference. What happens with your statement is, first x1
gets assigned the value of x2
, which is 1. Then, x2
gets assigned the value of x1
, which was 2, but is now 1.
If you were to inline everything, it might look something like this:
// using pointers because references can't be rebound
double *less, *greater;
if (x1 <= x2)
{
less = &x1;
greater = &x2;
}
else
{
// in your case, this is the branch taken
less = &x2;
greater = &x1;
}
x1 = *less; // less points to x2, so now both x1 and x2 = 1
x2 = *greater; // greater points to x1, and x1 = 1, so this assignment is redundant
I think part of your confusion comes from thinking (or hoping) that the assignments would happen simultaneously, but they don't. When you assign a tuple
or a pair
, the sub-objects are assigned in order, from left to right.
The problem is that std::minmax()
accepts two references and returns a pair of references. In particular, in your case it will return a pair where the first element is a reference to x2
, and the second element is a reference to x1
.
On the left side of the assignment, on the other hand, you have:
std::tie(x1, x2)
Which also creates a pair of references (ok, a tuple of two references actually, but that doesn't matter), but this time the first element of the pair is a reference to x1
, while the second element is a reference to x2
.
Then, you assign the pair returned by std::minmax()
to the pair returned by std::tie
, which means that x1
gets assigned the value of x2
(which is 1
) first; after that, x2
gets assigned the new value of x1
(once again, that's because std::minmax()
returned a pair of references, so the second element of that pair "sees" the side-effect of the assignment to x1
), which is now 1
.
This should explain the output.
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